Browse Source
Fully migrates debug commands to Lua and organizes them into logical
groups.
The CLI `+` syntax now runs Lua, e.g.:
```bash
build/devilutionx '+dev.player.trn.plr("infra")'
```
Chat hotkeys run Lua code if they start with `/lua`, e.g.:
```ini
[NetMsg]
QuickMessage1=/lua message(dev.player.info())
```
pull/6795/head
38 changed files with 1429 additions and 1227 deletions
@ -0,0 +1,133 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/display.hpp" |
||||||
|
|
||||||
|
#include <array> |
||||||
|
#include <optional> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "debug.h" |
||||||
|
#include "lighting.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "player.h" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdShowGrid(std::optional<bool> on) |
||||||
|
{ |
||||||
|
DebugGrid = on.value_or(!DebugGrid); |
||||||
|
return StrCat("Tile grid highlighting: ", DebugGrid ? "On" : "Off"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdVision(std::optional<bool> on) |
||||||
|
{ |
||||||
|
DebugVision = on.value_or(!DebugVision); |
||||||
|
return StrCat("Vision highlighting: ", DebugVision ? "On" : "Off"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdPath(std::optional<bool> on) |
||||||
|
{ |
||||||
|
DebugPath = on.value_or(!DebugPath); |
||||||
|
return StrCat("Path highlighting: ", DebugPath ? "On" : "Off"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdFullbright(std::optional<bool> on) |
||||||
|
{ |
||||||
|
ToggleLighting(); |
||||||
|
return StrCat("Fullbright: ", DisableLighting ? "On" : "Off"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdShowTileData(std::optional<std::string_view> dataType) |
||||||
|
{ |
||||||
|
static const std::array<std::string_view, 21> DataTypes { |
||||||
|
"dPiece", |
||||||
|
"dTransVal", |
||||||
|
"dLight", |
||||||
|
"dPreLight", |
||||||
|
"dFlags", |
||||||
|
"dPlayer", |
||||||
|
"dMonster", |
||||||
|
"dCorpse", |
||||||
|
"dObject", |
||||||
|
"dItem", |
||||||
|
"dSpecial", |
||||||
|
"coords", |
||||||
|
"cursorcoords", |
||||||
|
"objectindex", |
||||||
|
"solid", |
||||||
|
"transparent", |
||||||
|
"trap", |
||||||
|
"AutomapView", |
||||||
|
"dungeon", |
||||||
|
"pdungeon", |
||||||
|
"Protected", |
||||||
|
}; |
||||||
|
if (!dataType.has_value()) { |
||||||
|
std::string result = "Valid values for the first argument:\nclear"; |
||||||
|
for (const std::string_view &str : DataTypes) |
||||||
|
StrAppend(result, ", ", str); |
||||||
|
return result; |
||||||
|
} |
||||||
|
if (*dataType == "clear") { |
||||||
|
SetDebugGridTextType(DebugGridTextItem::None); |
||||||
|
return "Tile data cleared."; |
||||||
|
} |
||||||
|
bool found = false; |
||||||
|
int index = 0; |
||||||
|
for (const std::string_view ¶m : DataTypes) { |
||||||
|
index++; |
||||||
|
if (*dataType != param) |
||||||
|
continue; |
||||||
|
found = true; |
||||||
|
auto newGridText = static_cast<DebugGridTextItem>(index); |
||||||
|
if (newGridText == GetDebugGridTextType()) { |
||||||
|
SetDebugGridTextType(DebugGridTextItem::None); |
||||||
|
return "Tile data: Off"; |
||||||
|
} |
||||||
|
SetDebugGridTextType(newGridText); |
||||||
|
break; |
||||||
|
} |
||||||
|
if (!found) { |
||||||
|
std::string result = "Invalid name! Valid names are:\nclear"; |
||||||
|
for (const std::string_view &str : DataTypes) |
||||||
|
StrAppend(result, ", ", str); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
return "Tile data: On"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdScrollView(std::optional<bool> on) |
||||||
|
{ |
||||||
|
DebugScrollViewEnabled = on.value_or(!DebugScrollViewEnabled); |
||||||
|
if (!DebugScrollViewEnabled) |
||||||
|
InitMultiView(); |
||||||
|
return StrCat("Scroll view: ", DebugScrollViewEnabled ? "On" : "Off"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdToggleFPS(std::optional<bool> on) |
||||||
|
{ |
||||||
|
frameflag = on.value_or(!frameflag); |
||||||
|
return StrCat("FPS counter: ", frameflag ? "On" : "Off"); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevDisplayModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "fps", "(name: string = nil)", "Toggle FPS display.", &DebugCmdToggleFPS); |
||||||
|
SetDocumented(table, "fullbright", "(on: boolean = nil)", "Toggle light shading.", &DebugCmdFullbright); |
||||||
|
SetDocumented(table, "grid", "(on: boolean = nil)", "Toggle showing the grid.", &DebugCmdShowGrid); |
||||||
|
SetDocumented(table, "path", "(on: boolean = nil)", "Toggle path debug rendering.", &DebugCmdPath); |
||||||
|
SetDocumented(table, "scrollView", "(on: boolean = nil)", "Toggle view scrolling via Shift+Mouse.", &DebugCmdScrollView); |
||||||
|
SetDocumented(table, "tileData", "(name: string = nil)", "Toggle showing tile data.", &DebugCmdShowTileData); |
||||||
|
SetDocumented(table, "vision", "(on: boolean = nil)", "Toggle vision debug rendering.", &DebugCmdVision); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevDisplayModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,73 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/items.hpp" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "cursor.h" |
||||||
|
#include "items.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "pack.h" |
||||||
|
#include "player.h" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdItemInfo() |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
Item *pItem = nullptr; |
||||||
|
if (!myPlayer.HoldItem.isEmpty()) { |
||||||
|
pItem = &myPlayer.HoldItem; |
||||||
|
} else if (pcursinvitem != -1) { |
||||||
|
if (pcursinvitem <= INVITEM_INV_LAST) |
||||||
|
pItem = &myPlayer.InvList[pcursinvitem - INVITEM_INV_FIRST]; |
||||||
|
else |
||||||
|
pItem = &myPlayer.SpdList[pcursinvitem - INVITEM_BELT_FIRST]; |
||||||
|
} else if (pcursitem != -1) { |
||||||
|
pItem = &Items[pcursitem]; |
||||||
|
} |
||||||
|
if (pItem != nullptr) { |
||||||
|
std::string_view netPackValidation { "N/A" }; |
||||||
|
if (gbIsMultiplayer) { |
||||||
|
ItemNetPack itemPack; |
||||||
|
Item unpacked; |
||||||
|
PackNetItem(*pItem, itemPack); |
||||||
|
netPackValidation = UnPackNetItem(myPlayer, itemPack, unpacked) ? "Success" : "Failure"; |
||||||
|
} |
||||||
|
return StrCat("Name: ", pItem->_iIName, |
||||||
|
"\nIDidx: ", pItem->IDidx, " (", AllItemsList[pItem->IDidx].iName, ")", |
||||||
|
"\nSeed: ", pItem->_iSeed, |
||||||
|
"\nCreateInfo: ", pItem->_iCreateInfo, |
||||||
|
"\nLevel: ", pItem->_iCreateInfo & CF_LEVEL, |
||||||
|
"\nOnly Good: ", ((pItem->_iCreateInfo & CF_ONLYGOOD) == 0) ? "False" : "True", |
||||||
|
"\nUnique Monster: ", ((pItem->_iCreateInfo & CF_UPER15) == 0) ? "False" : "True", |
||||||
|
"\nDungeon Item: ", ((pItem->_iCreateInfo & CF_UPER1) == 0) ? "False" : "True", |
||||||
|
"\nUnique Item: ", ((pItem->_iCreateInfo & CF_UNIQUE) == 0) ? "False" : "True", |
||||||
|
"\nSmith: ", ((pItem->_iCreateInfo & CF_SMITH) == 0) ? "False" : "True", |
||||||
|
"\nSmith Premium: ", ((pItem->_iCreateInfo & CF_SMITHPREMIUM) == 0) ? "False" : "True", |
||||||
|
"\nBoy: ", ((pItem->_iCreateInfo & CF_BOY) == 0) ? "False" : "True", |
||||||
|
"\nWitch: ", ((pItem->_iCreateInfo & CF_WITCH) == 0) ? "False" : "True", |
||||||
|
"\nHealer: ", ((pItem->_iCreateInfo & CF_HEALER) == 0) ? "False" : "True", |
||||||
|
"\nPregen: ", ((pItem->_iCreateInfo & CF_PREGEN) == 0) ? "False" : "True", |
||||||
|
"\nNet Validation: ", netPackValidation); |
||||||
|
} |
||||||
|
return StrCat("Num items: ", ActiveItemCount); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevItemsModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "info", "()", "Show info of currently selected item.", &DebugCmdItemInfo); |
||||||
|
SetDocumented(table, "spawn", "(name: string)", "Attempt to generate an item.", &DebugSpawnItem); |
||||||
|
SetDocumented(table, "spawnUnique", "(name: string)", "Attempt to generate a unique item.", &DebugSpawnUniqueItem); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevItemsModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,124 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/level.hpp" |
||||||
|
|
||||||
|
#include <cstdio> |
||||||
|
#include <optional> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "diablo.h" |
||||||
|
#include "levels/gendung.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "lua/modules/dev/level/map.hpp" |
||||||
|
#include "lua/modules/dev/level/warp.hpp" |
||||||
|
#include "monster.h" |
||||||
|
#include "objects.h" |
||||||
|
#include "player.h" |
||||||
|
#include "utils/endian_stream.hpp" |
||||||
|
#include "utils/file_util.h" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string ExportDun() |
||||||
|
{ |
||||||
|
std::string levelName = StrCat(currlevel, "-", glSeedTbl[currlevel], ".dun"); |
||||||
|
std::string cmdLabel = "[exportdun] "; |
||||||
|
|
||||||
|
FILE *dunFile = OpenFile(levelName.c_str(), "ab"); |
||||||
|
|
||||||
|
WriteLE16(dunFile, DMAXX); |
||||||
|
WriteLE16(dunFile, DMAXY); |
||||||
|
|
||||||
|
/** Tiles. */ |
||||||
|
for (int y = 0; y < DMAXY; y++) { |
||||||
|
for (int x = 0; x < DMAXX; x++) { |
||||||
|
WriteLE16(dunFile, dungeon[x][y]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** Padding */ |
||||||
|
for (int y = 16; y < MAXDUNY - 16; y++) { |
||||||
|
for (int x = 16; x < MAXDUNX - 16; x++) { |
||||||
|
WriteLE16(dunFile, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** Monsters */ |
||||||
|
for (int y = 16; y < MAXDUNY - 16; y++) { |
||||||
|
for (int x = 16; x < MAXDUNX - 16; x++) { |
||||||
|
uint16_t monsterId = 0; |
||||||
|
if (dMonster[x][y] > 0) { |
||||||
|
for (int i = 0; i < 157; i++) { |
||||||
|
if (MonstConvTbl[i] == Monsters[std::abs(dMonster[x][y]) - 1].type().type) { |
||||||
|
monsterId = i + 1; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
WriteLE16(dunFile, monsterId); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** Objects */ |
||||||
|
for (int y = 16; y < MAXDUNY - 16; y++) { |
||||||
|
for (int x = 16; x < MAXDUNX - 16; x++) { |
||||||
|
uint16_t objectId = 0; |
||||||
|
Object *object = FindObjectAtPosition({ x, y }, false); |
||||||
|
if (object != nullptr) { |
||||||
|
for (int i = 0; i < 147; i++) { |
||||||
|
if (ObjTypeConv[i] == object->_otype) { |
||||||
|
objectId = i; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
WriteLE16(dunFile, objectId); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** Transparency */ |
||||||
|
for (int y = 16; y < MAXDUNY - 16; y++) { |
||||||
|
for (int x = 16; x < MAXDUNX - 16; x++) { |
||||||
|
WriteLE16(dunFile, dTransVal[x][y]); |
||||||
|
} |
||||||
|
} |
||||||
|
std::fclose(dunFile); |
||||||
|
|
||||||
|
return StrCat("Successfully exported ", levelName, "."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdResetLevel(uint8_t level, std::optional<int> seed) |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
if (level > (gbIsHellfire ? 24 : 16)) |
||||||
|
return StrCat("Level ", level, " does not exist!"); |
||||||
|
if (myPlayer.isOnLevel(level)) |
||||||
|
return "Unable to reset dungeon levels occupied by players!"; |
||||||
|
|
||||||
|
myPlayer._pLvlVisited[level] = false; |
||||||
|
DeltaClearLevel(level); |
||||||
|
|
||||||
|
if (seed.has_value()) { |
||||||
|
glSeedTbl[level] = *seed; |
||||||
|
return StrCat("Successfully reset level ", level, " with seed ", *seed, "."); |
||||||
|
} |
||||||
|
return StrCat("Successfully reset level ", level, "."); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevLevelModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "exportDun", "()", "Save the current level as a dun-file.", &ExportDun); |
||||||
|
SetDocumented(table, "map", "", "Automap-related commands.", LuaDevLevelMapModule(lua)); |
||||||
|
SetDocumented(table, "reset", "(n: number, seed: number = nil)", "Resets specified level.", &DebugCmdResetLevel); |
||||||
|
SetDocumented(table, "warp", "", "Warp to a level or a custom map.", LuaDevLevelWarpModule(lua)); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevLevelModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,41 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/level/map.hpp" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "automap.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdMapReveal() |
||||||
|
{ |
||||||
|
for (int x = 0; x < DMAXX; x++) |
||||||
|
for (int y = 0; y < DMAXY; y++) |
||||||
|
UpdateAutomapExplorer({ x, y }, MAP_EXP_SHRINE); |
||||||
|
return "Automap fully explored."; |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdMapHide() |
||||||
|
{ |
||||||
|
for (int x = 0; x < DMAXX; x++) |
||||||
|
for (int y = 0; y < DMAXY; y++) |
||||||
|
AutomapView[x][y] = MAP_EXP_NONE; |
||||||
|
return "Automap exploration removed."; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevLevelMapModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "hide", "()", "Hide the map.", &DebugCmdMapHide); |
||||||
|
SetDocumented(table, "reveal", "()", "Reveal the map.", &DebugCmdMapReveal); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevLevelMapModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,82 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/level/warp.hpp" |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <string> |
||||||
|
#include <string_view> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "debug.h" |
||||||
|
#include "interfac.h" |
||||||
|
#include "levels/setmaps.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "player.h" |
||||||
|
#include "quests.h" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdWarpToDungeonLevel(uint8_t level) |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
if (level > (gbIsHellfire ? 24 : 16)) |
||||||
|
return StrCat("Level ", level, " does not exist!"); |
||||||
|
if (!setlevel && myPlayer.isOnLevel(level)) |
||||||
|
return StrCat("You are already on level ", level, "!"); |
||||||
|
|
||||||
|
StartNewLvl(myPlayer, (level != 21) ? interface_mode::WM_DIABNEXTLVL : interface_mode::WM_DIABTOWNWARP, level); |
||||||
|
return StrCat("Moved you to level ", level, "."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdWarpToQuestLevel(uint8_t level) |
||||||
|
{ |
||||||
|
if (level < 1) |
||||||
|
return StrCat("Quest level number must be 1 or higher!"); |
||||||
|
if (setlevel && setlvlnum == level) |
||||||
|
return StrCat("You are already on quest level", level, "!"); |
||||||
|
|
||||||
|
for (Quest &quest : Quests) { |
||||||
|
if (level != quest._qslvl) |
||||||
|
continue; |
||||||
|
|
||||||
|
setlvltype = quest._qlvltype; |
||||||
|
StartNewLvl(*MyPlayer, WM_DIABSETLVL, level); |
||||||
|
|
||||||
|
return StrCat("Moved you to quest level ", QuestLevelNames[level], "."); |
||||||
|
} |
||||||
|
|
||||||
|
return StrCat("Quest level ", level, " does not exist!"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdWarpToCustomMap(std::string_view path, int dunType, int x, int y) |
||||||
|
{ |
||||||
|
if (path.empty()) return "path is required"; |
||||||
|
if (dunType < DTYPE_CATHEDRAL || dunType > DTYPE_LAST) return "invalid dunType"; |
||||||
|
|
||||||
|
const Point spawn { x, y }; |
||||||
|
if (!InDungeonBounds(spawn)) return "spawn location is out of bounds"; |
||||||
|
|
||||||
|
TestMapPath = StrCat(path, ".dun"); |
||||||
|
setlvltype = static_cast<dungeon_type>(dunType); |
||||||
|
ViewPosition = spawn; |
||||||
|
|
||||||
|
StartNewLvl(*MyPlayer, WM_DIABSETLVL, SL_NONE); |
||||||
|
|
||||||
|
return StrCat("Moved you to ", TestMapPath, "."); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevLevelWarpModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "dungeon", "(n: number)", "Go to dungeon level (0 for town).", &DebugCmdWarpToDungeonLevel); |
||||||
|
SetDocumented(table, "map", "(path: string, dunType: number, x: number, y: number)", "Go to custom {path}.dun level", &DebugCmdWarpToCustomMap); |
||||||
|
SetDocumented(table, "quest", "(n: number)", "Go to quest level.", &DebugCmdWarpToQuestLevel); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevLevelWarpModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,175 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/monsters.hpp" |
||||||
|
|
||||||
|
#include <optional> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "levels/gendung.h" |
||||||
|
#include "lighting.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "monstdat.h" |
||||||
|
#include "monster.h" |
||||||
|
#include "player.h" |
||||||
|
#include "utils/str_case.hpp" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdSpawnUniqueMonster(std::string name, std::optional<unsigned> countOpt) |
||||||
|
{ |
||||||
|
if (leveltype == DTYPE_TOWN) return "Can't spawn monsters in town"; |
||||||
|
if (name.empty()) return "name is required"; |
||||||
|
const unsigned count = countOpt.value_or(1); |
||||||
|
if (count < 1) return "count must be positive"; |
||||||
|
|
||||||
|
AsciiStrToLower(name); |
||||||
|
|
||||||
|
int mtype = -1; |
||||||
|
UniqueMonsterType uniqueIndex = UniqueMonsterType::None; |
||||||
|
for (size_t i = 0; UniqueMonstersData[i].mtype != MT_INVALID; i++) { |
||||||
|
auto mondata = UniqueMonstersData[i]; |
||||||
|
const std::string monsterName = AsciiStrToLower(mondata.mName); |
||||||
|
if (monsterName.find(name) == std::string::npos) |
||||||
|
continue; |
||||||
|
mtype = mondata.mtype; |
||||||
|
uniqueIndex = static_cast<UniqueMonsterType>(i); |
||||||
|
if (monsterName == name) // to support partial name matching but always choose the correct monster if full name is given
|
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (mtype == -1) return "Monster not found"; |
||||||
|
|
||||||
|
size_t id = MaxLvlMTypes - 1; |
||||||
|
bool found = false; |
||||||
|
|
||||||
|
for (size_t i = 0; i < LevelMonsterTypeCount; i++) { |
||||||
|
if (LevelMonsterTypes[i].type == mtype) { |
||||||
|
id = i; |
||||||
|
found = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!found) { |
||||||
|
CMonster &monsterType = LevelMonsterTypes[id]; |
||||||
|
monsterType.type = static_cast<_monster_id>(mtype); |
||||||
|
InitMonsterGFX(monsterType); |
||||||
|
InitMonsterSND(monsterType); |
||||||
|
monsterType.placeFlags |= PLACE_SCATTER; |
||||||
|
monsterType.corpseId = 1; |
||||||
|
} |
||||||
|
|
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
|
||||||
|
unsigned spawnedMonster = 0; |
||||||
|
|
||||||
|
auto ret = Crawl(0, MaxCrawlRadius, [&](Displacement displacement) -> std::optional<std::string> { |
||||||
|
Point pos = myPlayer.position.tile + displacement; |
||||||
|
if (dPlayer[pos.x][pos.y] != 0 || dMonster[pos.x][pos.y] != 0) |
||||||
|
return {}; |
||||||
|
if (!IsTileWalkable(pos)) |
||||||
|
return {}; |
||||||
|
|
||||||
|
Monster *monster = AddMonster(pos, myPlayer._pdir, id, true); |
||||||
|
if (monster == nullptr) |
||||||
|
return StrCat("Spawned ", spawnedMonster, " monsters. (Unable to spawn more)"); |
||||||
|
PrepareUniqueMonst(*monster, uniqueIndex, 0, 0, UniqueMonstersData[static_cast<size_t>(uniqueIndex)]); |
||||||
|
monster->corpseId = 1; |
||||||
|
spawnedMonster += 1; |
||||||
|
|
||||||
|
if (spawnedMonster >= count) |
||||||
|
return StrCat("Spawned ", spawnedMonster, " monsters."); |
||||||
|
|
||||||
|
return {}; |
||||||
|
}); |
||||||
|
|
||||||
|
if (!ret.has_value()) |
||||||
|
ret = StrCat("Spawned ", spawnedMonster, " monsters. (Unable to spawn more)"); |
||||||
|
return *ret; |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdSpawnMonster(std::string name, std::optional<unsigned> countOpt) |
||||||
|
{ |
||||||
|
if (leveltype == DTYPE_TOWN) return "Can't spawn monsters in town"; |
||||||
|
if (name.empty()) return "name is required"; |
||||||
|
const unsigned count = countOpt.value_or(1); |
||||||
|
if (count < 1) return "count must be positive"; |
||||||
|
|
||||||
|
AsciiStrToLower(name); |
||||||
|
|
||||||
|
int mtype = -1; |
||||||
|
|
||||||
|
for (int i = 0; i < NUM_MTYPES; i++) { |
||||||
|
auto mondata = MonstersData[i]; |
||||||
|
const std::string monsterName = AsciiStrToLower(mondata.name); |
||||||
|
if (monsterName.find(name) == std::string::npos) |
||||||
|
continue; |
||||||
|
mtype = i; |
||||||
|
if (monsterName == name) // to support partial name matching but always choose the correct monster if full name is given
|
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (mtype == -1) return "Monster not found"; |
||||||
|
|
||||||
|
size_t id = MaxLvlMTypes - 1; |
||||||
|
bool found = false; |
||||||
|
|
||||||
|
for (size_t i = 0; i < LevelMonsterTypeCount; i++) { |
||||||
|
if (LevelMonsterTypes[i].type == mtype) { |
||||||
|
id = i; |
||||||
|
found = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!found) { |
||||||
|
CMonster &monsterType = LevelMonsterTypes[id]; |
||||||
|
monsterType.type = static_cast<_monster_id>(mtype); |
||||||
|
InitMonsterGFX(monsterType); |
||||||
|
InitMonsterSND(monsterType); |
||||||
|
monsterType.placeFlags |= PLACE_SCATTER; |
||||||
|
monsterType.corpseId = 1; |
||||||
|
} |
||||||
|
|
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
|
||||||
|
unsigned spawnedMonster = 0; |
||||||
|
|
||||||
|
auto ret = Crawl(0, MaxCrawlRadius, [&](Displacement displacement) -> std::optional<std::string> { |
||||||
|
Point pos = myPlayer.position.tile + displacement; |
||||||
|
if (dPlayer[pos.x][pos.y] != 0 || dMonster[pos.x][pos.y] != 0) |
||||||
|
return {}; |
||||||
|
if (!IsTileWalkable(pos)) |
||||||
|
return {}; |
||||||
|
|
||||||
|
if (AddMonster(pos, myPlayer._pdir, id, true) == nullptr) |
||||||
|
return StrCat("Spawned ", spawnedMonster, " monsters. (Unable to spawn more)"); |
||||||
|
spawnedMonster += 1; |
||||||
|
|
||||||
|
if (spawnedMonster >= count) |
||||||
|
return StrCat("Spawned ", spawnedMonster, " monsters."); |
||||||
|
|
||||||
|
return {}; |
||||||
|
}); |
||||||
|
|
||||||
|
if (!ret.has_value()) |
||||||
|
return StrCat("Spawned ", spawnedMonster, " monsters. (Unable to spawn more)"); |
||||||
|
return *ret; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevMonstersModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "spawn", "(name: string, count: number = 1)", "Spawn monster(s)", &DebugCmdSpawnMonster); |
||||||
|
SetDocumented(table, "spawnUnique", "(name: string, count: number = 1)", "Spawn unique monster(s)", &DebugCmdSpawnUniqueMonster); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevMonstersModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,109 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/player.hpp" |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "debug.h" |
||||||
|
#include "engine/assets.hpp" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "lua/modules/dev/player/gold.hpp" |
||||||
|
#include "lua/modules/dev/player/spells.hpp" |
||||||
|
#include "lua/modules/dev/player/stats.hpp" |
||||||
|
#include "player.h" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdArrow(std::string_view effect) |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
|
||||||
|
myPlayer._pIFlags &= ~ItemSpecialEffect::FireArrows; |
||||||
|
myPlayer._pIFlags &= ~ItemSpecialEffect::LightningArrows; |
||||||
|
|
||||||
|
if (effect == "normal") { |
||||||
|
// we removed the parameter at the top
|
||||||
|
} else if (effect == "fire") { |
||||||
|
myPlayer._pIFlags |= ItemSpecialEffect::FireArrows; |
||||||
|
} else if (effect == "lightning") { |
||||||
|
myPlayer._pIFlags |= ItemSpecialEffect::LightningArrows; |
||||||
|
} else if (effect == "spectral") { |
||||||
|
myPlayer._pIFlags |= (ItemSpecialEffect::FireArrows | ItemSpecialEffect::LightningArrows); |
||||||
|
} else { |
||||||
|
return "Invalid effect!"; |
||||||
|
} |
||||||
|
|
||||||
|
return StrCat("Arrows changed to: ", effect); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdGodMode(std::optional<bool> on) |
||||||
|
{ |
||||||
|
DebugGodMode = on.value_or(!DebugGodMode); |
||||||
|
return StrCat("God mode: ", DebugGodMode ? "On" : "Off"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdPlayerInfo(std::optional<uint8_t> id) |
||||||
|
{ |
||||||
|
const uint8_t playerId = id.value_or(0); |
||||||
|
if (playerId >= Players.size()) |
||||||
|
return StrCat("Invalid player ID (max: ", Players.size() - 1, ")"); |
||||||
|
Player &player = Players[playerId]; |
||||||
|
if (!player.plractive) |
||||||
|
return StrCat("Player ", playerId, " is not active!"); |
||||||
|
|
||||||
|
const Point target = player.GetTargetPosition(); |
||||||
|
return StrCat("Plr ", playerId, " is ", player._pName, |
||||||
|
"\nLvl: ", player.plrlevel, " Changing: ", player._pLvlChanging, |
||||||
|
"\nTile.x: ", player.position.tile.x, " Tile.y: ", player.position.tile.y, " Target.x: ", target.x, " Target.y: ", target.y, |
||||||
|
"\nMode: ", player._pmode, " destAction: ", player.destAction, " walkpath[0]: ", player.walkpath[0], |
||||||
|
"\nInvincible: ", player._pInvincible ? 1 : 0, " HitPoints: ", player._pHitPoints); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugSetPlayerTrn(std::string_view path) |
||||||
|
{ |
||||||
|
if (!path.empty()) { |
||||||
|
if (const AssetRef ref = FindAsset(path); !ref.ok()) { |
||||||
|
const char *error = ref.error(); |
||||||
|
return error == nullptr || *error == '\0' ? StrCat("File not found: ", path) : error; |
||||||
|
} |
||||||
|
} |
||||||
|
debugTRN = path; |
||||||
|
Player &player = *MyPlayer; |
||||||
|
InitPlayerGFX(player); |
||||||
|
StartStand(player, player._pdir); |
||||||
|
return path.empty() ? "TRN unset" : "TRN set"; |
||||||
|
} |
||||||
|
|
||||||
|
sol::table LuaDevPlayerTrnModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "mon", "(name: string)", "Set player TRN to monsters\\monsters\\${name}.trn", |
||||||
|
[](std::string_view name) { return DebugSetPlayerTrn(StrCat("monsters\\monsters\\", name, ".trn")); }); |
||||||
|
SetDocumented(table, "plr", "(name: string)", "Set player TRN to plrgfx\\${name}.trn", |
||||||
|
[](std::string_view name) { return DebugSetPlayerTrn(StrCat("plrgfx\\", name, ".trn")); }); |
||||||
|
SetDocumented(table, "clear", "()", "Unset player TRN", |
||||||
|
[]() { return DebugSetPlayerTrn(""); }); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevPlayerModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "arrow", "(effect: 'normal'|'fire'|'lightning'|'explosion')", "Set arrow effect.", &DebugCmdArrow); |
||||||
|
SetDocumented(table, "god", "(on: boolean = nil)", "Toggle god mode.", &DebugCmdGodMode); |
||||||
|
SetDocumented(table, "gold", "", "Adjust player gold.", LuaDevPlayerGoldModule(lua)); |
||||||
|
SetDocumented(table, "info", "(id: number = 0)", "Show player info.", &DebugCmdPlayerInfo); |
||||||
|
SetDocumented(table, "spells", "", "Adjust player spells.", LuaDevPlayerSpellsModule(lua)); |
||||||
|
SetDocumented(table, "stats", "", "Adjust player stats (Strength, HP, etc).", LuaDevPlayerStatsModule(lua)); |
||||||
|
SetDocumented(table, "trn", "", "Set player TRN to '${name}.trn'", LuaDevPlayerTrnModule(lua)); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,11 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevPlayerModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,101 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/player/gold.hpp" |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <optional> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "items.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "player.h" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdGiveGoldCheat(std::optional<int> amount) |
||||||
|
{ |
||||||
|
int goldToAdd = amount.value_or(GOLD_MAX_LIMIT * InventoryGridCells); |
||||||
|
if (goldToAdd <= 0) return "amount must be positive"; |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
const int goldAmountBefore = myPlayer._pGold; |
||||||
|
for (int8_t &itemIndex : myPlayer.InvGrid) { |
||||||
|
if (itemIndex < 0) |
||||||
|
continue; |
||||||
|
|
||||||
|
Item &item = myPlayer.InvList[itemIndex != 0 ? itemIndex - 1 : myPlayer._pNumInv]; |
||||||
|
|
||||||
|
if (itemIndex != 0) { |
||||||
|
if ((!item.isGold() && !item.isEmpty()) || (item.isGold() && item._ivalue == GOLD_MAX_LIMIT)) |
||||||
|
continue; |
||||||
|
} else { |
||||||
|
if (item.isEmpty()) { |
||||||
|
MakeGoldStack(item, 0); |
||||||
|
myPlayer._pNumInv++; |
||||||
|
itemIndex = myPlayer._pNumInv; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int goldThatCanBeAdded = (GOLD_MAX_LIMIT - item._ivalue); |
||||||
|
if (goldThatCanBeAdded >= goldToAdd) { |
||||||
|
item._ivalue += goldToAdd; |
||||||
|
myPlayer._pGold += goldToAdd; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
item._ivalue += goldThatCanBeAdded; |
||||||
|
goldToAdd -= goldThatCanBeAdded; |
||||||
|
myPlayer._pGold += goldThatCanBeAdded; |
||||||
|
} |
||||||
|
|
||||||
|
CalcPlrInv(myPlayer, true); |
||||||
|
|
||||||
|
return StrCat("Set your gold to ", myPlayer._pGold, ", added ", myPlayer._pGold - goldAmountBefore, "."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdTakeGoldCheat(std::optional<int> amount) |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
int goldToRemove = amount.value_or(GOLD_MAX_LIMIT * InventoryGridCells); |
||||||
|
if (goldToRemove <= 0) return "amount must be positive"; |
||||||
|
|
||||||
|
const int goldAmountBefore = myPlayer._pGold; |
||||||
|
for (auto itemIndex : myPlayer.InvGrid) { |
||||||
|
itemIndex -= 1; |
||||||
|
|
||||||
|
if (itemIndex < 0) |
||||||
|
continue; |
||||||
|
|
||||||
|
Item &item = myPlayer.InvList[itemIndex]; |
||||||
|
if (!item.isGold()) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (item._ivalue >= goldToRemove) { |
||||||
|
myPlayer._pGold -= goldToRemove; |
||||||
|
item._ivalue -= goldToRemove; |
||||||
|
if (item._ivalue == 0) |
||||||
|
myPlayer.RemoveInvItem(itemIndex); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
myPlayer._pGold -= item._ivalue; |
||||||
|
goldToRemove -= item._ivalue; |
||||||
|
myPlayer.RemoveInvItem(itemIndex); |
||||||
|
} |
||||||
|
|
||||||
|
return StrCat("Set your gold to ", myPlayer._pGold, ", removed ", goldAmountBefore - myPlayer._pGold, "."); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevPlayerGoldModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "give", "(amount: number = MAX)", "Gives the player gold.", &DebugCmdGiveGoldCheat); |
||||||
|
SetDocumented(table, "take", "(amount: number = MAX)", "Takes the player's gold away.", &DebugCmdTakeGoldCheat); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevPlayerGoldModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,39 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/player/spells.hpp" |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "msg.h" |
||||||
|
#include "spelldat.h" |
||||||
|
#include "spells.h" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
namespace { |
||||||
|
std::string DebugCmdSetSpellsLevel(uint8_t level) |
||||||
|
{ |
||||||
|
for (uint8_t i = static_cast<uint8_t>(SpellID::Firebolt); i < MAX_SPELLS; i++) { |
||||||
|
if (GetSpellBookLevel(static_cast<SpellID>(i)) != -1) { |
||||||
|
NetSendCmdParam2(true, CMD_CHANGE_SPELL_LEVEL, i, level); |
||||||
|
} |
||||||
|
} |
||||||
|
if (level == 0) |
||||||
|
MyPlayer->_pMemSpells = 0; |
||||||
|
|
||||||
|
return StrCat("Set all spell levels to ", level); |
||||||
|
} |
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevPlayerSpellsModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "setLevel", "(level: number)", "Set spell level for all spells.", &DebugCmdSetSpellsLevel); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevPlayerSpellsModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,100 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/player/stats.hpp" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "engine/backbuffer_state.hpp" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "player.h" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdLevelUp(std::optional<int> levels) |
||||||
|
{ |
||||||
|
if (!levels.has_value()) *levels = 1; |
||||||
|
if (*levels <= 0) return "amount must be positive"; |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
for (int i = 0; i < *levels; i++) |
||||||
|
NetSendCmd(true, CMD_CHEAT_EXPERIENCE); |
||||||
|
return StrCat("New character level: ", myPlayer.getCharacterLevel() + *levels); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdMaxStats() |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
ModifyPlrStr(myPlayer, myPlayer.GetMaximumAttributeValue(CharacterAttribute::Strength) - myPlayer._pBaseStr); |
||||||
|
ModifyPlrMag(myPlayer, myPlayer.GetMaximumAttributeValue(CharacterAttribute::Magic) - myPlayer._pBaseMag); |
||||||
|
ModifyPlrDex(myPlayer, myPlayer.GetMaximumAttributeValue(CharacterAttribute::Dexterity) - myPlayer._pBaseDex); |
||||||
|
ModifyPlrVit(myPlayer, myPlayer.GetMaximumAttributeValue(CharacterAttribute::Vitality) - myPlayer._pBaseVit); |
||||||
|
return "Set all character base attributes to maximum."; |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdMinStats() |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
ModifyPlrStr(myPlayer, -myPlayer._pBaseStr); |
||||||
|
ModifyPlrMag(myPlayer, -myPlayer._pBaseMag); |
||||||
|
ModifyPlrDex(myPlayer, -myPlayer._pBaseDex); |
||||||
|
ModifyPlrVit(myPlayer, -myPlayer._pBaseVit); |
||||||
|
return "Set all character base attributes to minimum."; |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdRefillHealthMana() |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
myPlayer.RestoreFullLife(); |
||||||
|
myPlayer.RestoreFullMana(); |
||||||
|
RedrawComponent(PanelDrawComponent::Health); |
||||||
|
RedrawComponent(PanelDrawComponent::Mana); |
||||||
|
return StrCat("Restored life and mana to full."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdChangeHealth(int change) |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
if (change == 0) |
||||||
|
return StrCat("Enter a value not equal to 0 to change life!"); |
||||||
|
|
||||||
|
int newHealth = myPlayer._pHitPoints + (change * 64); |
||||||
|
SetPlayerHitPoints(myPlayer, newHealth); |
||||||
|
if (newHealth <= 0) |
||||||
|
SyncPlrKill(myPlayer, DeathReason::MonsterOrTrap); |
||||||
|
|
||||||
|
return StrCat("Changed life by ", change); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdChangeMana(int change) |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
if (change == 0) |
||||||
|
return StrCat("Enter a value not equal to 0 to change mana!"); |
||||||
|
|
||||||
|
int newMana = myPlayer._pMana + (change * 64); |
||||||
|
myPlayer._pMana = newMana; |
||||||
|
myPlayer._pManaBase = myPlayer._pMana + myPlayer._pMaxManaBase - myPlayer._pMaxMana; |
||||||
|
RedrawComponent(PanelDrawComponent::Mana); |
||||||
|
|
||||||
|
return StrCat("Changed mana by ", change); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevPlayerStatsModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "adjustHealth", "(amount: number)", "Adjust HP (amount can be negative)", &DebugCmdChangeHealth); |
||||||
|
SetDocumented(table, "adjustMana", "(amount: number)", "Adjust mana (amount can be negative)", &DebugCmdChangeMana); |
||||||
|
SetDocumented(table, "levelUp", "(amount: number = 1)", "Level the player up.", &DebugCmdLevelUp); |
||||||
|
SetDocumented(table, "rejuvenate", "()", "Refill health", &DebugCmdRefillHealthMana); |
||||||
|
SetDocumented(table, "setAttrToMax", "()", "Set Str, Mag, Dex, and Vit to maximum.", &DebugCmdMaxStats); |
||||||
|
SetDocumented(table, "setAttrToMin", "()", "Set Str, Mag, Dex, and Vit to minimum.", &DebugCmdMinStats); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevPlayerStatsModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,56 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/quests.hpp" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "debug.h" |
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "utils/str_case.hpp" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
namespace { |
||||||
|
|
||||||
|
std::string DebugCmdSearchMonster(std::string_view name) |
||||||
|
{ |
||||||
|
if (name.empty()) return "Missing monster name!"; |
||||||
|
AddDebugAutomapMonsterHighlight(AsciiStrToLower(name)); |
||||||
|
return StrCat("Added automap marker for monster ", name, "."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdSearchItem(std::string_view name) |
||||||
|
{ |
||||||
|
if (name.empty()) return "Missing item name!"; |
||||||
|
AddDebugAutomapItemHighlight(AsciiStrToLower(name)); |
||||||
|
return StrCat("Added automap marker for item ", name, "."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdSearchObject(std::string_view name) |
||||||
|
{ |
||||||
|
if (name.empty()) return "Missing object name!"; |
||||||
|
AddDebugAutomapObjectHighlight(AsciiStrToLower(name)); |
||||||
|
return StrCat("Added automap marker for object ", name, "."); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdClearSearch() |
||||||
|
{ |
||||||
|
ClearDebugAutomapHighlights(); |
||||||
|
return "Removed all automap search markers."; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevSearchModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "clear", "()", "Clear search results from the map.", &DebugCmdClearSearch); |
||||||
|
SetDocumented(table, "item", "(name: string)", "Search the map for an item.", &DebugCmdSearchItem); |
||||||
|
SetDocumented(table, "monster", "(name: string)", "Search the map for a monster.", &DebugCmdSearchMonster); |
||||||
|
SetDocumented(table, "object", "(name: string)", "Search the map for an object.", &DebugCmdSearchObject); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevSearchModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,93 @@ |
|||||||
|
#ifdef _DEBUG |
||||||
|
#include "lua/modules/dev/towners.hpp" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
#include "lua/metadoc.hpp" |
||||||
|
#include "player.h" |
||||||
|
#include "spells.h" |
||||||
|
#include "towners.h" |
||||||
|
#include "utils/str_cat.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
namespace { |
||||||
|
|
||||||
|
std::unordered_map<std::string_view, _talker_id> TownerShortNameToTownerId = { |
||||||
|
{ "griswold", _talker_id::TOWN_SMITH }, |
||||||
|
{ "smith", _talker_id::TOWN_SMITH }, |
||||||
|
{ "pepin", _talker_id::TOWN_HEALER }, |
||||||
|
{ "healer", _talker_id::TOWN_HEALER }, |
||||||
|
{ "ogden", _talker_id::TOWN_TAVERN }, |
||||||
|
{ "tavern", _talker_id::TOWN_TAVERN }, |
||||||
|
{ "cain", _talker_id::TOWN_STORY }, |
||||||
|
{ "story", _talker_id::TOWN_STORY }, |
||||||
|
{ "farnham", _talker_id::TOWN_DRUNK }, |
||||||
|
{ "drunk", _talker_id::TOWN_DRUNK }, |
||||||
|
{ "adria", _talker_id::TOWN_WITCH }, |
||||||
|
{ "witch", _talker_id::TOWN_WITCH }, |
||||||
|
{ "gillian", _talker_id::TOWN_BMAID }, |
||||||
|
{ "bmaid", _talker_id::TOWN_BMAID }, |
||||||
|
{ "wirt", _talker_id ::TOWN_PEGBOY }, |
||||||
|
{ "pegboy", _talker_id ::TOWN_PEGBOY }, |
||||||
|
{ "lester", _talker_id ::TOWN_FARMER }, |
||||||
|
{ "farmer", _talker_id ::TOWN_FARMER }, |
||||||
|
{ "girl", _talker_id ::TOWN_GIRL }, |
||||||
|
{ "nut", _talker_id::TOWN_COWFARM }, |
||||||
|
{ "cowfarm", _talker_id::TOWN_COWFARM }, |
||||||
|
}; |
||||||
|
|
||||||
|
std::string DebugCmdVisitTowner(std::string_view name) |
||||||
|
{ |
||||||
|
Player &myPlayer = *MyPlayer; |
||||||
|
|
||||||
|
if (setlevel || !myPlayer.isOnLevel(0)) |
||||||
|
return StrCat("This command is only available in Town!"); |
||||||
|
|
||||||
|
if (name.empty()) { |
||||||
|
std::string ret; |
||||||
|
ret = StrCat("Please provide the name of a Towner: "); |
||||||
|
for (const auto &[name, _] : TownerShortNameToTownerId) { |
||||||
|
ret += ' '; |
||||||
|
ret.append(name); |
||||||
|
} |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
auto it = TownerShortNameToTownerId.find(name); |
||||||
|
if (it == TownerShortNameToTownerId.end()) |
||||||
|
return StrCat(name, " is invalid!"); |
||||||
|
|
||||||
|
for (const Towner &towner : Towners) { |
||||||
|
if (towner._ttype != it->second) continue; |
||||||
|
CastSpell( |
||||||
|
static_cast<int>(MyPlayerId), |
||||||
|
SpellID::Teleport, |
||||||
|
myPlayer.position.tile, |
||||||
|
towner.position, |
||||||
|
/*spllvl=*/1); |
||||||
|
return StrCat("Moved you to ", name, "."); |
||||||
|
} |
||||||
|
|
||||||
|
return StrCat("Unable to locate ", name, "!"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string DebugCmdTalkToTowner(std::string_view name) |
||||||
|
{ |
||||||
|
if (!DebugTalkToTowner(name)) return StrCat("Towner not found!"); |
||||||
|
return StrCat("Opened ", name, " talk window."); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
sol::table LuaDevTownersModule(sol::state_view &lua) |
||||||
|
{ |
||||||
|
sol::table table = lua.create_table(); |
||||||
|
SetDocumented(table, "talk", "(name: string)", "Talk to towner.", &DebugCmdTalkToTowner); |
||||||
|
SetDocumented(table, "visit", "(name: string)", "Teleport to towner.", &DebugCmdVisitTowner); |
||||||
|
return table; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#pragma once |
||||||
|
#ifdef _DEBUG |
||||||
|
#include <sol/sol.hpp> |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
sol::table LuaDevTownersModule(sol::state_view &lua); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
#endif // _DEBUG
|
||||||
Loading…
Reference in new issue