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