Browse Source

Lua: Improve function/property handling

1. Follows advice from
   https://sol2.readthedocs.io/en/latest/functions.html to use
   `set_function` when binding functions.
2. Adds autocomplete support for userdata methods.
3. Simplifies property bindings and improves string handling.
pull/8079/head
Gleb Mazovetskiy 8 months ago committed by Anders Jenbo
parent
commit
17e6da40f8
  1. 76
      Source/lua/autocomplete.cpp
  2. 98
      Source/lua/metadoc.hpp
  3. 4
      Source/lua/modules/audio.cpp
  4. 16
      Source/lua/modules/dev.cpp
  5. 14
      Source/lua/modules/dev/display.cpp
  6. 6
      Source/lua/modules/dev/items.cpp
  7. 10
      Source/lua/modules/dev/level.cpp
  8. 4
      Source/lua/modules/dev/level/map.cpp
  9. 6
      Source/lua/modules/dev/level/warp.cpp
  10. 4
      Source/lua/modules/dev/monsters.cpp
  11. 22
      Source/lua/modules/dev/player.cpp
  12. 4
      Source/lua/modules/dev/player/gold.cpp
  13. 2
      Source/lua/modules/dev/player/spells.cpp
  14. 12
      Source/lua/modules/dev/player/stats.cpp
  15. 8
      Source/lua/modules/dev/quests.cpp
  16. 8
      Source/lua/modules/dev/search.cpp
  17. 4
      Source/lua/modules/dev/towners.cpp
  18. 4
      Source/lua/modules/hellfire.cpp
  19. 10
      Source/lua/modules/i18n.cpp
  20. 177
      Source/lua/modules/items.cpp
  21. 14
      Source/lua/modules/player.cpp
  22. 6
      Source/lua/modules/render.cpp
  23. 4
      Source/lua/modules/towners.cpp

76
Source/lua/autocomplete.cpp

@ -3,6 +3,7 @@
#include <algorithm>
#include <cstddef>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
@ -121,8 +122,36 @@ ValueInfo GetValueInfo(const sol::table &table, std::string_view key, const sol:
return info;
}
ValueInfo GetValueInfoForUserdata(const sol::userdata &obj, std::string_view key, const sol::object &value, std::optional<LuaUserdataMemberType> memberType)
{
ValueInfo info;
if (value.get_type() == sol::type::userdata) {
info.callable = false;
return info;
}
if (std::optional<std::string> signature = GetLuaUserdataSignature(obj, key); signature.has_value()) {
info.signature = *std::move(signature);
}
if (std::optional<std::string> docstring = GetLuaUserdataDocstring(obj, key); docstring.has_value()) {
info.docstring = *std::move(docstring);
}
if (memberType.has_value()) {
info.callable = *memberType == LuaUserdataMemberType::MemberFunction;
} else {
info.callable = value.get_type() == sol::type::function;
}
return info;
}
struct UserdataQuery {
const sol::userdata *obj;
bool colonAccess;
};
void SuggestionsFromTable(const sol::table &table, std::string_view prefix,
size_t maxSuggestions, ankerl::unordered_dense::set<LuaAutocompleteSuggestion> &out)
size_t maxSuggestions, ankerl::unordered_dense::set<LuaAutocompleteSuggestion> &out,
std::optional<UserdataQuery> userdataQuery = std::nullopt)
{
for (const auto &[key, value] : table) {
if (key.get_type() == sol::type::string) {
@ -136,7 +165,20 @@ void SuggestionsFromTable(const sol::table &table, std::string_view prefix,
|| keyStr.find("") != std::string::npos
|| keyStr.find("🔩") != std::string::npos)
continue;
ValueInfo info = GetValueInfo(table, keyStr, value);
ValueInfo info;
std::optional<LuaUserdataMemberType> memberType;
if (userdataQuery.has_value()) {
memberType = GetLuaUserdataMemberType(*userdataQuery->obj, keyStr, value);
const bool requiresColonAccess = memberType.has_value()
? *memberType == LuaUserdataMemberType::MemberFunction
: value.get_type() == sol::type::function;
if (userdataQuery->colonAccess != requiresColonAccess) {
continue;
}
info = GetValueInfoForUserdata(*userdataQuery->obj, keyStr, value, memberType);
} else {
info = GetValueInfo(table, keyStr, value);
}
std::string completionText = keyStr.substr(prefix.size());
LuaAutocompleteSuggestion suggestion { std::move(keyStr), std::move(completionText) };
if (info.callable) {
@ -144,6 +186,9 @@ void SuggestionsFromTable(const sol::table &table, std::string_view prefix,
suggestion.cursorAdjust = -1;
}
if (!info.signature.empty()) {
if (memberType.has_value() && memberType != LuaUserdataMemberType::MemberFunction) {
StrAppend(suggestion.displayText, ": ");
}
StrAppend(suggestion.displayText, info.signature);
}
if (!info.docstring.empty()) {
@ -164,6 +209,15 @@ void SuggestionsFromTable(const sol::table &table, std::string_view prefix,
}
}
void SuggestionsFromUserdata(UserdataQuery query, std::string_view prefix,
size_t maxSuggestions, ankerl::unordered_dense::set<LuaAutocompleteSuggestion> &out)
{
const auto &meta = query.obj->get<std::optional<sol::object>>(sol::metatable_key);
if (meta.has_value() && meta->get_type() == sol::type::table) {
SuggestionsFromTable(meta->as<sol::table>(), prefix, maxSuggestions, out, query);
}
}
} // namespace
void GetLuaAutocompleteSuggestions(std::string_view text, const sol::environment &lua,
@ -174,8 +228,9 @@ void GetLuaAutocompleteSuggestions(std::string_view text, const sol::environment
std::string_view token = GetLastToken(text);
const char prevChar = token.data() == text.data() ? '\0' : *(token.data() - 1);
if (prevChar == '(' || prevChar == ',') return;
const size_t dotPos = token.rfind('.');
const size_t dotPos = token.find_last_of(".:");
const std::string_view prefix = token.substr(dotPos + 1);
const char completionChar = dotPos != std::string_view::npos ? token[dotPos] : '\0';
token.remove_suffix(token.size() - (dotPos == std::string_view::npos ? 0 : dotPos));
ankerl::unordered_dense::set<LuaAutocompleteSuggestion> suggestions;
@ -192,13 +247,20 @@ void GetLuaAutocompleteSuggestions(std::string_view text, const sol::environment
}
} else {
std::optional<sol::object> obj = lua;
for (const std::string_view part : SplitByChar(token, '.')) {
obj = obj->as<sol::table>().get<std::optional<sol::object>>(part);
if (!obj.has_value() || obj->get_type() != sol::type::table)
return;
for (const std::string_view partDot : SplitByChar(token, '.')) {
for (const std::string_view part : SplitByChar(partDot, ':')) {
obj = obj->as<sol::table>().get<std::optional<sol::object>>(part);
if (!obj.has_value() || !(obj->get_type() == sol::type::table || obj->get_type() == sol::type::userdata)) {
return;
}
}
}
if (obj->get_type() == sol::type::table) {
addSuggestions(obj->as<sol::table>());
} else if (obj->get_type() == sol::type::userdata) {
const sol::userdata &data = obj->as<sol::userdata>();
SuggestionsFromUserdata(UserdataQuery { &data, completionChar == ':' },
prefix, maxSuggestions, suggestions);
}
}

98
Source/lua/metadoc.hpp

@ -1,13 +1,23 @@
#pragma once
#include <sol/sol.hpp>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <sol/sol.hpp>
#include "utils/str_cat.hpp"
namespace devilution {
enum class LuaUserdataMemberType : uint8_t {
ReadonlyProperty,
Property,
MemberFunction,
Constructor,
};
inline std::string LuaSignatureKey(std::string_view key)
{
return StrCat("__sig_", key);
@ -18,33 +28,70 @@ inline std::string LuaDocstringKey(std::string_view key)
return StrCat("__doc_", key);
}
inline std::string LuaUserdataMemberTypeKey(std::string_view key)
{
return StrCat("__udt_", key);
}
namespace lua_metadoc_internal {
template <typename U>
inline void SetUsertypeSignatureAndDocstring(sol::usertype<U> &table, std::string_view key, const char *signature, const char *doc, LuaUserdataMemberType memberType)
{
table.set(LuaSignatureKey(key), sol::var(signature));
table.set(LuaDocstringKey(key), sol::var(doc));
table.set(LuaUserdataMemberTypeKey(key), sol::var(static_cast<uint8_t>(memberType)));
}
} // namespace lua_metadoc_internal
template <typename U, typename T>
void SetDocumented(sol::usertype<U> &table, std::string_view key, std::string_view signature, std::string_view doc, T &&value)
void LuaSetDocFn(sol::usertype<U> &table, std::string_view key, const char *signature, const char *doc, T &&value)
{
table[key] = std::forward<T>(value);
// TODO: figure out a way to set signature and docstring.
table.set_function(key, std::forward<T>(value));
lua_metadoc_internal::SetUsertypeSignatureAndDocstring(table, key, signature, doc, LuaUserdataMemberType::MemberFunction);
}
template <typename U, typename G>
void LuaSetDocReadonlyProperty(sol::usertype<U> &table, std::string_view key, const char *type, const char *doc, G &&getter)
{
table.set(key, sol::readonly_property(std::forward<G>(getter)));
lua_metadoc_internal::SetUsertypeSignatureAndDocstring(table, key, type, doc, LuaUserdataMemberType::ReadonlyProperty);
}
template <typename U, typename G, typename S>
void SetDocumented(sol::usertype<U> &table, std::string_view key, std::string_view signature, std::string_view doc, G &&getter, S &&setter)
void LuaSetDocProperty(sol::usertype<U> &table, std::string_view key, const char *type, const char *doc, G &&getter, S &&setter)
{
table.set(key, sol::property(std::forward<G>(getter), std::forward<S>(setter)));
lua_metadoc_internal::SetUsertypeSignatureAndDocstring(table, key, type, doc, LuaUserdataMemberType::Property);
}
template <typename U, typename F>
void LuaSetDocProperty(sol::usertype<U> &table, std::string_view key, const char *type, const char *doc, F U::*&&value)
{
table.set(key, value);
lua_metadoc_internal::SetUsertypeSignatureAndDocstring(table, key, type, doc, LuaUserdataMemberType::Property);
}
template <typename T>
void LuaSetDoc(sol::table &table, std::string_view key, const char *signature, const char *doc, T &&value)
{
table[key] = sol::property(std::forward<G>(getter), std::forward<S>(setter));
// TODO: figure out a way to set signature and docstring.
table.set(key, std::forward<T>(value));
table.set(LuaSignatureKey(key), signature);
table.set(LuaDocstringKey(key), doc);
}
template <typename T>
void SetDocumented(sol::table &table, std::string_view key, std::string_view signature, std::string_view doc, T &&value)
void LuaSetDocFn(sol::table &table, std::string_view key, const char *signature, const char *doc, T &&value)
{
table[key] = std::forward<T>(value);
table[LuaSignatureKey(key)] = signature;
table[LuaDocstringKey(key)] = doc;
table.set_function(key, std::forward<T>(value));
table.set(LuaSignatureKey(key), signature);
table.set(LuaDocstringKey(key), doc);
}
template <typename T>
void SetWithSignature(sol::table &table, std::string_view key, std::string_view signature, T &&value)
void LuaSetDocFn(sol::table &table, std::string_view key, std::string_view signature, T &&value)
{
table[key] = std::forward<T>(value);
table[LuaSignatureKey(key)] = signature;
table.set_function(key, std::forward<T>(value));
table.set(LuaSignatureKey(key), signature);
}
inline std::optional<std::string> GetSignature(const sol::table &table, std::string_view key)
@ -57,4 +104,25 @@ inline std::optional<std::string> GetDocstring(const sol::table &table, std::str
return table.get<std::optional<std::string>>(LuaDocstringKey(key));
}
inline std::optional<std::string> GetLuaUserdataSignature(const sol::userdata &obj, std::string_view key)
{
return obj.get<std::optional<std::string>>(LuaSignatureKey(key));
}
inline std::optional<std::string> GetLuaUserdataDocstring(const sol::userdata &obj, std::string_view key)
{
return obj.get<std::optional<std::string>>(LuaDocstringKey(key));
}
inline std::optional<LuaUserdataMemberType> GetLuaUserdataMemberType(const sol::userdata &obj, std::string_view key, const sol::object &value)
{
std::optional<uint8_t> result = obj.get<std::optional<uint8_t>>(LuaUserdataMemberTypeKey(key));
if (!result.has_value()) {
if (value.get_type() == sol::type::userdata) return LuaUserdataMemberType::Property;
if (value.get_type() == sol::type::function && key == "new") return LuaUserdataMemberType::Constructor;
return std::nullopt;
}
return static_cast<LuaUserdataMemberType>(*result);
}
} // namespace devilution

4
Source/lua/modules/audio.cpp

@ -19,10 +19,10 @@ bool IsValidSfx(int16_t psfx)
sol::table LuaAudioModule(sol::state_view &lua)
{
sol::table table = lua.create_table();
SetWithSignature(table,
LuaSetDocFn(table,
"playSfx", "(id: number)",
[](int16_t psfx) { if (IsValidSfx(psfx)) PlaySFX(static_cast<SfxID>(psfx)); });
SetWithSignature(table,
LuaSetDocFn(table,
"playSfxLoc", "(id: number, x: number, y: number)",
[](int16_t psfx, int x, int y) { if (IsValidSfx(psfx)) PlaySfxLoc(static_cast<SfxID>(psfx), { x, y }); });
return table;

16
Source/lua/modules/dev.cpp

@ -18,14 +18,14 @@ namespace devilution {
sol::table LuaDevModule(sol::state_view &lua)
{
sol::table table = lua.create_table();
SetDocumented(table, "display", "", "Debugging HUD and rendering commands.", LuaDevDisplayModule(lua));
SetDocumented(table, "items", "", "Item-related commands.", LuaDevItemsModule(lua));
SetDocumented(table, "level", "", "Level-related commands.", LuaDevLevelModule(lua));
SetDocumented(table, "monsters", "", "Monster-related commands.", LuaDevMonstersModule(lua));
SetDocumented(table, "player", "", "Player-related commands.", LuaDevPlayerModule(lua));
SetDocumented(table, "quests", "", "Quest-related commands.", LuaDevQuestsModule(lua));
SetDocumented(table, "search", "", "Search the map for monsters / items / objects.", LuaDevSearchModule(lua));
SetDocumented(table, "towners", "", "Town NPC commands.", LuaDevTownersModule(lua));
LuaSetDoc(table, "display", "", "Debugging HUD and rendering commands.", LuaDevDisplayModule(lua));
LuaSetDoc(table, "items", "", "Item-related commands.", LuaDevItemsModule(lua));
LuaSetDoc(table, "level", "", "Level-related commands.", LuaDevLevelModule(lua));
LuaSetDoc(table, "monsters", "", "Monster-related commands.", LuaDevMonstersModule(lua));
LuaSetDoc(table, "player", "", "Player-related commands.", LuaDevPlayerModule(lua));
LuaSetDoc(table, "quests", "", "Quest-related commands.", LuaDevQuestsModule(lua));
LuaSetDoc(table, "search", "", "Search the map for monsters / items / objects.", LuaDevSearchModule(lua));
LuaSetDoc(table, "towners", "", "Town NPC commands.", LuaDevTownersModule(lua));
return table;
}

14
Source/lua/modules/dev/display.cpp

@ -121,13 +121,13 @@ std::string DebugCmdToggleFPS(std::optional<bool> on)
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);
LuaSetDocFn(table, "fps", "(name: string = nil)", "Toggle FPS display.", &DebugCmdToggleFPS);
LuaSetDocFn(table, "fullbright", "(on: boolean = nil)", "Toggle light shading.", &DebugCmdFullbright);
LuaSetDocFn(table, "grid", "(on: boolean = nil)", "Toggle showing the grid.", &DebugCmdShowGrid);
LuaSetDocFn(table, "path", "(on: boolean = nil)", "Toggle path debug rendering.", &DebugCmdPath);
LuaSetDocFn(table, "scrollView", "(on: boolean = nil)", "Toggle view scrolling via Shift+Mouse.", &DebugCmdScrollView);
LuaSetDocFn(table, "tileData", "(name: string = nil)", "Toggle showing tile data.", &DebugCmdShowTileData);
LuaSetDocFn(table, "vision", "(on: boolean = nil)", "Toggle vision debug rendering.", &DebugCmdVision);
return table;
}

6
Source/lua/modules/dev/items.cpp

@ -194,9 +194,9 @@ std::string DebugSpawnUniqueItem(std::string itemName)
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);
LuaSetDocFn(table, "info", "()", "Show info of currently selected item.", &DebugCmdItemInfo);
LuaSetDocFn(table, "spawn", "(name: string)", "Attempt to generate an item.", &DebugSpawnItem);
LuaSetDocFn(table, "spawnUnique", "(name: string)", "Attempt to generate a unique item.", &DebugSpawnUniqueItem);
return table;
}

10
Source/lua/modules/dev/level.cpp

@ -122,11 +122,11 @@ std::string DebugCmdLevelSeed(std::optional<uint8_t> level)
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, "seed", "(level: number = nil)", "Get the seed of the current or given level.", &DebugCmdLevelSeed);
SetDocumented(table, "warp", "", "Warp to a level or a custom map.", LuaDevLevelWarpModule(lua));
LuaSetDocFn(table, "exportDun", "()", "Save the current level as a dun-file.", &ExportDun);
LuaSetDocFn(table, "map", "", "Automap-related commands.", LuaDevLevelMapModule(lua));
LuaSetDocFn(table, "reset", "(n: number, seed: number = nil)", "Resets specified level.", &DebugCmdResetLevel);
LuaSetDocFn(table, "seed", "(level: number = nil)", "Get the seed of the current or given level.", &DebugCmdLevelSeed);
LuaSetDocFn(table, "warp", "", "Warp to a level or a custom map.", LuaDevLevelWarpModule(lua));
return table;
}

4
Source/lua/modules/dev/level/map.cpp

@ -32,8 +32,8 @@ std::string DebugCmdMapHide()
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);
LuaSetDocFn(table, "hide", "()", "Hide the map.", &DebugCmdMapHide);
LuaSetDocFn(table, "reveal", "()", "Reveal the map.", &DebugCmdMapReveal);
return table;
}

6
Source/lua/modules/dev/level/warp.cpp

@ -72,9 +72,9 @@ std::string DebugCmdWarpToCustomMap(std::string_view path, int dunType, int x, i
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);
LuaSetDocFn(table, "dungeon", "(n: number)", "Go to dungeon level (0 for town).", &DebugCmdWarpToDungeonLevel);
LuaSetDocFn(table, "map", "(path: string, dunType: number, x: number, y: number)", "Go to custom {path}.dun level", &DebugCmdWarpToCustomMap);
LuaSetDocFn(table, "quest", "(n: number)", "Go to quest level.", &DebugCmdWarpToQuestLevel);
return table;
}

4
Source/lua/modules/dev/monsters.cpp

@ -172,8 +172,8 @@ std::string DebugCmdSpawnMonster(std::string name, std::optional<unsigned> count
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);
LuaSetDocFn(table, "spawn", "(name: string, count: number = 1)", "Spawn monster(s)", &DebugCmdSpawnMonster);
LuaSetDocFn(table, "spawnUnique", "(name: string, count: number = 1)", "Spawn unique monster(s)", &DebugCmdSpawnUniqueMonster);
return table;
}

22
Source/lua/modules/dev/player.cpp

@ -81,11 +81,11 @@ std::string DebugSetPlayerTrn(std::string_view path)
sol::table LuaDevPlayerTrnModule(sol::state_view &lua)
{
sol::table table = lua.create_table();
SetDocumented(table, "mon", "(name: string)", "Set player TRN to monsters\\${name}.trn",
LuaSetDocFn(table, "mon", "(name: string)", "Set player TRN to monsters\\${name}.trn",
[](std::string_view name) { return DebugSetPlayerTrn(StrCat("monsters\\", name, ".trn")); });
SetDocumented(table, "plr", "(name: string)", "Set player TRN to plrgfx\\${name}.trn",
LuaSetDocFn(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",
LuaSetDocFn(table, "clear", "()", "Unset player TRN",
[]() { return DebugSetPlayerTrn(""); });
return table;
}
@ -101,14 +101,14 @@ std::string DebugCmdInvisible(std::optional<bool> on)
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));
SetDocumented(table, "invisible", "(on: boolean = nil)", "Toggle invisibility.", &DebugCmdInvisible);
LuaSetDocFn(table, "arrow", "(effect: 'normal'|'fire'|'lightning'|'explosion')", "Set arrow effect.", &DebugCmdArrow);
LuaSetDocFn(table, "god", "(on: boolean = nil)", "Toggle god mode.", &DebugCmdGodMode);
LuaSetDoc(table, "gold", "", "Adjust player gold.", LuaDevPlayerGoldModule(lua));
LuaSetDocFn(table, "info", "(id: number = 0)", "Show player info.", &DebugCmdPlayerInfo);
LuaSetDoc(table, "spells", "", "Adjust player spells.", LuaDevPlayerSpellsModule(lua));
LuaSetDoc(table, "stats", "", "Adjust player stats (Strength, HP, etc).", LuaDevPlayerStatsModule(lua));
LuaSetDoc(table, "trn", "", "Set player TRN to '${name}.trn'", LuaDevPlayerTrnModule(lua));
LuaSetDocFn(table, "invisible", "(on: boolean = nil)", "Toggle invisibility.", &DebugCmdInvisible);
return table;
}

4
Source/lua/modules/dev/player/gold.cpp

@ -92,8 +92,8 @@ std::string DebugCmdTakeGoldCheat(std::optional<int> amount)
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);
LuaSetDocFn(table, "give", "(amount: number = MAX)", "Gives the player gold.", &DebugCmdGiveGoldCheat);
LuaSetDocFn(table, "take", "(amount: number = MAX)", "Takes the player's gold away.", &DebugCmdTakeGoldCheat);
return table;
}

2
Source/lua/modules/dev/player/spells.cpp

@ -31,7 +31,7 @@ std::string DebugCmdSetSpellsLevel(uint8_t level)
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);
LuaSetDocFn(table, "setLevel", "(level: number)", "Set spell level for all spells.", &DebugCmdSetSpellsLevel);
return table;
}

12
Source/lua/modules/dev/player/stats.cpp

@ -87,12 +87,12 @@ std::string DebugCmdChangeMana(int change)
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);
LuaSetDocFn(table, "adjustHealth", "(amount: number)", "Adjust HP (amount can be negative)", &DebugCmdChangeHealth);
LuaSetDocFn(table, "adjustMana", "(amount: number)", "Adjust mana (amount can be negative)", &DebugCmdChangeMana);
LuaSetDocFn(table, "levelUp", "(amount: number = 1)", "Level the player up.", &DebugCmdLevelUp);
LuaSetDocFn(table, "rejuvenate", "()", "Refill health", &DebugCmdRefillHealthMana);
LuaSetDocFn(table, "setAttrToMax", "()", "Set Str, Mag, Dex, and Vit to maximum.", &DebugCmdMaxStats);
LuaSetDocFn(table, "setAttrToMin", "()", "Set Str, Mag, Dex, and Vit to minimum.", &DebugCmdMinStats);
return table;
}

8
Source/lua/modules/dev/quests.cpp

@ -63,10 +63,10 @@ std::string DebugCmdQuestsInfo()
sol::table LuaDevQuestsModule(sol::state_view &lua)
{
sol::table table = lua.create_table();
SetDocumented(table, "activate", "(id: number)", "Activate the given quest.", &DebugCmdEnableQuest);
SetDocumented(table, "activateAll", "()", "Activate all available quests.", &DebugCmdEnableQuests);
SetDocumented(table, "all", "()", "Information on all available quest.", &DebugCmdQuestsInfo);
SetDocumented(table, "info", "(id: number)", "Information on the given quest.", &DebugCmdQuestInfo);
LuaSetDocFn(table, "activate", "(id: number)", "Activate the given quest.", &DebugCmdEnableQuest);
LuaSetDocFn(table, "activateAll", "()", "Activate all available quests.", &DebugCmdEnableQuests);
LuaSetDocFn(table, "all", "()", "Information on all available quest.", &DebugCmdQuestsInfo);
LuaSetDocFn(table, "info", "(id: number)", "Information on the given quest.", &DebugCmdQuestInfo);
return table;
}

8
Source/lua/modules/dev/search.cpp

@ -45,10 +45,10 @@ std::string DebugCmdClearSearch()
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);
LuaSetDocFn(table, "clear", "()", "Clear search results from the map.", &DebugCmdClearSearch);
LuaSetDocFn(table, "item", "(name: string)", "Search the map for an item.", &DebugCmdSearchItem);
LuaSetDocFn(table, "monster", "(name: string)", "Search the map for a monster.", &DebugCmdSearchMonster);
LuaSetDocFn(table, "object", "(name: string)", "Search the map for an object.", &DebugCmdSearchObject);
return table;
}

4
Source/lua/modules/dev/towners.cpp

@ -99,8 +99,8 @@ std::string DebugCmdTalkToTowner(std::string_view name)
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);
LuaSetDocFn(table, "talk", "(name: string)", "Talk to towner.", &DebugCmdTalkToTowner);
LuaSetDocFn(table, "visit", "(name: string)", "Teleport to towner.", &DebugCmdVisitTowner);
return table;
}

4
Source/lua/modules/hellfire.cpp

@ -10,8 +10,8 @@ namespace devilution {
sol::table LuaHellfireModule(sol::state_view &lua)
{
sol::table table = lua.create_table();
SetWithSignature(table, "loadData", "()", []() { LoadHellfireArchives(); });
SetWithSignature(table, "enable", "()", []() { gbIsHellfire = true; });
LuaSetDocFn(table, "loadData", "()", LoadHellfireArchives);
LuaSetDocFn(table, "enable", "()", []() { gbIsHellfire = true; });
return table;
}

10
Source/lua/modules/i18n.cpp

@ -13,17 +13,17 @@ namespace devilution {
sol::table LuaI18nModule(sol::state_view &lua)
{
sol::table table = lua.create_table();
SetDocumented(table, "language_code", "()",
LuaSetDocFn(table, "language_code", "()",
"Returns the current language code", GetLanguageCode);
SetDocumented(table, "translate", "(text: string)",
LuaSetDocFn(table, "translate", "(text: string)",
"Translates the given string", [](const char *key) { return LanguageTranslate(key); });
SetDocumented(table, "plural_translate", "(singular: string, plural: string, count: integer)",
LuaSetDocFn(table, "plural_translate", "(singular: string, plural: string, count: integer)",
"Returns a singular or plural translation for the given keys and count", [](const char *singular, std::string_view plural, int count) {
return fmt::format(fmt::runtime(LanguagePluralTranslate(singular, plural, count)), count);
});
SetDocumented(table, "particular_translate", "(context: string, text: string)",
LuaSetDocFn(table, "particular_translate", "(context: string, text: string)",
"Returns the translation for the given context identifier and key.", LanguageParticularTranslate);
SetDocumented(table, "is_small_font_tall", "()",
LuaSetDocFn(table, "is_small_font_tall", "()",
"Whether the language's small font is tall (16px)", IsSmallFontTall);
return table;
}

177
Source/lua/modules/items.cpp

@ -1,12 +1,13 @@
#include "lua/modules/items.hpp"
#include <optional>
#include <string_view>
#include <sol/sol.hpp>
#include "items.h"
#include "lua/metadoc.hpp"
#include "player.h"
#include "utils/utf8.hpp"
namespace devilution {
@ -18,98 +19,94 @@ void InitItemUserType(sol::state_view &lua)
sol::usertype<Item> itemType = lua.new_usertype<Item>(sol::no_constructor);
// Member variables
SetDocumented(itemType, "seed", "number", "Randomly generated identifier", [](const Item &i) { return i._iSeed; }, [](Item &i, unsigned int val) { i._iSeed = val; });
SetDocumented(itemType, "createInfo", "number", "Creation flags", [](const Item &i) { return i._iCreateInfo; }, [](Item &i, unsigned int val) { i._iCreateInfo = val; });
SetDocumented(itemType, "type", "ItemType", "Item type", [](const Item &i) { return i._itype; }, [](Item &i, int val) { i._itype = static_cast<ItemType>(val); });
SetDocumented(itemType, "animFlag", "boolean", "Animation flag", [](const Item &i) { return i._iAnimFlag; }, [](Item &i, bool val) { i._iAnimFlag = val; });
SetDocumented(itemType, "position", "Point", "Item world position", [](const Item &i) { return i.position; }, [](Item &i, Point val) { i.position = val; });
LuaSetDocProperty(itemType, "seed", "number", "Randomly generated identifier", &Item::_iSeed);
LuaSetDocProperty(itemType, "createInfo", "number", "Creation flags", &Item::_iCreateInfo);
LuaSetDocProperty(itemType, "type", "ItemType", "Item type", &Item::_itype);
LuaSetDocProperty(itemType, "animFlag", "boolean", "Animation flag", &Item::_iAnimFlag);
LuaSetDocProperty(itemType, "position", "Point", "Item world position", &Item::position);
// TODO: Add AnimationInfo usertype
// SetDocumented(itemType, "animInfo", "AnimationInfo", "Animation information", [](const Item &i) { return i.AnimInfo; }, [](Item &i, AnimationInfo val) { i.AnimInfo = val; });
SetDocumented(itemType, "delFlag", "boolean", "Deletion flag", [](const Item &i) { return i._iDelFlag; }, [](Item &i, bool val) { i._iDelFlag = val; });
SetDocumented(itemType, "selectionRegion", "number", "Selection region", [](const Item &i) { return static_cast<int>(i.selectionRegion); }, [](Item &i, int val) { i.selectionRegion = static_cast<SelectionRegion>(val); });
SetDocumented(itemType, "postDraw", "boolean", "Post-draw flag", [](const Item &i) { return i._iPostDraw; }, [](Item &i, bool val) { i._iPostDraw = val; });
SetDocumented(itemType, "identified", "boolean", "Identified flag", [](const Item &i) { return i._iIdentified; }, [](Item &i, bool val) { i._iIdentified = val; });
SetDocumented(itemType, "magical", "number", "Item quality", [](const Item &i) { return static_cast<int>(i._iMagical); }, [](Item &i, int val) { i._iMagical = static_cast<item_quality>(val); });
SetDocumented(itemType, "name", "string", "Item name", [](const Item &i) { return std::string(i._iName); }, [](Item &i, const std::string &val) {
std::strncpy(i._iName, val.c_str(), sizeof(i._iName));
i._iName[sizeof(i._iName) - 1] = '\0'; });
SetDocumented(itemType, "iName", "string", "Identified item name", [](const Item &i) { return std::string(i._iIName); }, [](Item &i, const std::string &val) {
std::strncpy(i._iIName, val.c_str(), sizeof(i._iIName));
i._iIName[sizeof(i._iIName) - 1] = '\0'; });
SetDocumented(itemType, "loc", "ItemEquipType", "Equipment location", [](const Item &i) { return i._iLoc; }, [](Item &i, int val) { i._iLoc = static_cast<item_equip_type>(val); });
SetDocumented(itemType, "class", "ItemClass", "Item class", [](const Item &i) { return i._iClass; }, [](Item &i, int val) { i._iClass = static_cast<item_class>(val); });
SetDocumented(itemType, "curs", "number", "Cursor index", [](const Item &i) { return i._iCurs; }, [](Item &i, int val) { i._iCurs = val; });
SetDocumented(itemType, "value", "number", "Item value", [](const Item &i) { return i._ivalue; }, [](Item &i, int val) { i._ivalue = val; });
SetDocumented(itemType, "ivalue", "number", "Identified item value", [](const Item &i) { return i._iIvalue; }, [](Item &i, int val) { i._iIvalue = val; });
SetDocumented(itemType, "minDam", "number", "Minimum damage", [](const Item &i) { return i._iMinDam; }, [](Item &i, int val) { i._iMinDam = val; });
SetDocumented(itemType, "maxDam", "number", "Maximum damage", [](const Item &i) { return i._iMaxDam; }, [](Item &i, int val) { i._iMaxDam = val; });
SetDocumented(itemType, "AC", "number", "Armor class", [](const Item &i) { return i._iAC; }, [](Item &i, int val) { i._iAC = val; });
SetDocumented(itemType, "flags", "ItemSpecialEffect", "Special effect flags", [](const Item &i) { return static_cast<int>(i._iFlags); }, [](Item &i, int val) { i._iFlags = static_cast<ItemSpecialEffect>(val); });
SetDocumented(itemType, "miscId", "ItemMiscID", "Miscellaneous ID", [](const Item &i) { return i._iMiscId; }, [](Item &i, int val) { i._iMiscId = static_cast<item_misc_id>(val); });
SetDocumented(itemType, "spell", "SpellID", "Spell", [](const Item &i) { return i._iSpell; }, [](Item &i, int val) { i._iSpell = static_cast<SpellID>(val); });
SetDocumented(itemType, "IDidx", "ItemIndex", "Base item index", [](const Item &i) { return i.IDidx; }, [](Item &i, int val) { i.IDidx = static_cast<_item_indexes>(val); });
SetDocumented(itemType, "charges", "number", "Number of charges", [](const Item &i) { return i._iCharges; }, [](Item &i, int val) { i._iCharges = val; });
SetDocumented(itemType, "maxCharges", "number", "Maximum charges", [](const Item &i) { return i._iMaxCharges; }, [](Item &i, int val) { i._iMaxCharges = val; });
SetDocumented(itemType, "durability", "number", "Durability", [](const Item &i) { return i._iDurability; }, [](Item &i, int val) { i._iDurability = val; });
SetDocumented(itemType, "maxDur", "number", "Maximum durability", [](const Item &i) { return i._iMaxDur; }, [](Item &i, int val) { i._iMaxDur = val; });
SetDocumented(itemType, "PLDam", "number", "Damage % bonus", [](const Item &i) { return i._iPLDam; }, [](Item &i, int val) { i._iPLDam = val; });
SetDocumented(itemType, "PLToHit", "number", "Chance to hit bonus", [](const Item &i) { return i._iPLToHit; }, [](Item &i, int val) { i._iPLToHit = val; });
SetDocumented(itemType, "PLAC", "number", "Armor class % bonus", [](const Item &i) { return i._iPLAC; }, [](Item &i, int val) { i._iPLAC = val; });
SetDocumented(itemType, "PLStr", "number", "Strength bonus", [](const Item &i) { return i._iPLStr; }, [](Item &i, int val) { i._iPLStr = val; });
SetDocumented(itemType, "PLMag", "number", "Magic bonus", [](const Item &i) { return i._iPLMag; }, [](Item &i, int val) { i._iPLMag = val; });
SetDocumented(itemType, "PLDex", "number", "Dexterity bonus", [](const Item &i) { return i._iPLDex; }, [](Item &i, int val) { i._iPLDex = val; });
SetDocumented(itemType, "PLVit", "number", "Vitality bonus", [](const Item &i) { return i._iPLVit; }, [](Item &i, int val) { i._iPLVit = val; });
SetDocumented(itemType, "PLFR", "number", "Fire resistance bonus", [](const Item &i) { return i._iPLFR; }, [](Item &i, int val) { i._iPLFR = val; });
SetDocumented(itemType, "PLLR", "number", "Lightning resistance bonus", [](const Item &i) { return i._iPLLR; }, [](Item &i, int val) { i._iPLLR = val; });
SetDocumented(itemType, "PLMR", "number", "Magic resistance bonus", [](const Item &i) { return i._iPLMR; }, [](Item &i, int val) { i._iPLMR = val; });
SetDocumented(itemType, "PLMana", "number", "Mana bonus", [](const Item &i) { return i._iPLMana; }, [](Item &i, int val) { i._iPLMana = val; });
SetDocumented(itemType, "PLHP", "number", "Life bonus", [](const Item &i) { return i._iPLHP; }, [](Item &i, int val) { i._iPLHP = val; });
SetDocumented(itemType, "PLDamMod", "number", "Damage modifier bonus", [](const Item &i) { return i._iPLDamMod; }, [](Item &i, int val) { i._iPLDamMod = val; });
SetDocumented(itemType, "PLGetHit", "number", "Damage from enemies bonus", [](const Item &i) { return i._iPLGetHit; }, [](Item &i, int val) { i._iPLGetHit = val; });
SetDocumented(itemType, "PLLight", "number", "Light bonus", [](const Item &i) { return i._iPLLight; }, [](Item &i, int val) { i._iPLLight = val; });
SetDocumented(itemType, "splLvlAdd", "number", "Spell level bonus", [](const Item &i) { return i._iSplLvlAdd; }, [](Item &i, int val) { i._iSplLvlAdd = val; });
SetDocumented(itemType, "request", "boolean", "Request flag", [](const Item &i) { return i._iRequest; }, [](Item &i, bool val) { i._iRequest = val; });
SetDocumented(itemType, "uid", "number", "Unique item ID", [](const Item &i) { return i._iUid; }, [](Item &i, int val) { i._iUid = val; });
SetDocumented(itemType, "fMinDam", "number", "Fire minimum damage", [](const Item &i) { return i._iFMinDam; }, [](Item &i, int val) { i._iFMinDam = val; });
SetDocumented(itemType, "fMaxDam", "number", "Fire maximum damage", [](const Item &i) { return i._iFMaxDam; }, [](Item &i, int val) { i._iFMaxDam = val; });
SetDocumented(itemType, "lMinDam", "number", "Lightning minimum damage", [](const Item &i) { return i._iLMinDam; }, [](Item &i, int val) { i._iLMinDam = val; });
SetDocumented(itemType, "lMaxDam", "number", "Lightning maximum damage", [](const Item &i) { return i._iLMaxDam; }, [](Item &i, int val) { i._iLMaxDam = val; });
SetDocumented(itemType, "PLEnAc", "number", "Damage target AC bonus", [](const Item &i) { return i._iPLEnAc; }, [](Item &i, int val) { i._iPLEnAc = val; });
SetDocumented(itemType, "prePower", "ItemEffectType", "Prefix power", [](const Item &i) { return i._iPrePower; }, [](Item &i, int val) { i._iPrePower = static_cast<item_effect_type>(val); });
SetDocumented(itemType, "sufPower", "ItemEffectType", "Suffix power", [](const Item &i) { return i._iSufPower; }, [](Item &i, int val) { i._iSufPower = static_cast<item_effect_type>(val); });
SetDocumented(itemType, "vAdd1", "number", "Value addition 1", [](const Item &i) { return i._iVAdd1; }, [](Item &i, int val) { i._iVAdd1 = val; });
SetDocumented(itemType, "vMult1", "number", "Value multiplier 1", [](const Item &i) { return i._iVMult1; }, [](Item &i, int val) { i._iVMult1 = val; });
SetDocumented(itemType, "vAdd2", "number", "Value addition 2", [](const Item &i) { return i._iVAdd2; }, [](Item &i, int val) { i._iVAdd2 = val; });
SetDocumented(itemType, "vMult2", "number", "Value multiplier 2", [](const Item &i) { return i._iVMult2; }, [](Item &i, int val) { i._iVMult2 = val; });
SetDocumented(itemType, "minStr", "number", "Minimum strength required", [](const Item &i) { return i._iMinStr; }, [](Item &i, int val) { i._iMinStr = val; });
SetDocumented(itemType, "minMag", "number", "Minimum magic required", [](const Item &i) { return i._iMinMag; }, [](Item &i, int val) { i._iMinMag = val; });
SetDocumented(itemType, "minDex", "number", "Minimum dexterity required", [](const Item &i) { return i._iMinDex; }, [](Item &i, int val) { i._iMinDex = val; });
SetDocumented(itemType, "statFlag", "boolean", "Equippable flag", [](const Item &i) { return i._iStatFlag; }, [](Item &i, bool val) { i._iStatFlag = val; });
SetDocumented(itemType, "damAcFlags", "ItemSpecialEffectHf", "Secondary special effect flags", [](const Item &i) { return i._iDamAcFlags; }, [](Item &i, int val) { i._iDamAcFlags = static_cast<ItemSpecialEffectHf>(val); });
SetDocumented(itemType, "buff", "number", "Secondary creation flags", [](const Item &i) { return i.dwBuff; }, [](Item &i, int val) { i.dwBuff = val; });
// LuaSetDocProperty(itemType, "animInfo", "AnimationInfo", "Animation information", &Item::AnimInfo);
LuaSetDocProperty(itemType, "delFlag", "boolean", "Deletion flag", &Item::_iDelFlag);
LuaSetDocProperty(itemType, "selectionRegion", "number", "Selection region", &Item::selectionRegion);
LuaSetDocProperty(itemType, "postDraw", "boolean", "Post-draw flag", &Item::_iPostDraw);
LuaSetDocProperty(itemType, "identified", "boolean", "Identified flag", &Item::_iIdentified);
LuaSetDocProperty(itemType, "magical", "number", "Item quality", &Item::_iMagical);
LuaSetDocProperty(itemType, "name", "string", "Item name", [](const Item &i) { return std::string_view(i._iName); }, [](Item &i, std::string_view val) { CopyUtf8(i._iName, val, sizeof(i._iName)); });
LuaSetDocProperty(itemType, "iName", "string", "Identified item name", [](const Item &i) { return std::string_view(i._iIName); }, [](Item &i, std::string_view val) { CopyUtf8(i._iIName, val, sizeof(i._iIName)); });
LuaSetDocProperty(itemType, "loc", "ItemEquipType", "Equipment location", &Item::_iLoc);
LuaSetDocProperty(itemType, "class", "ItemClass", "Item class", &Item::_iClass);
LuaSetDocProperty(itemType, "curs", "number", "Cursor index", &Item::_iCurs);
LuaSetDocProperty(itemType, "value", "number", "Item value", &Item::_ivalue);
LuaSetDocProperty(itemType, "ivalue", "number", "Identified item value", &Item::_iIvalue);
LuaSetDocProperty(itemType, "minDam", "number", "Minimum damage", &Item::_iMinDam);
LuaSetDocProperty(itemType, "maxDam", "number", "Maximum damage", &Item::_iMaxDam);
LuaSetDocProperty(itemType, "AC", "number", "Armor class", &Item::_iAC);
LuaSetDocProperty(itemType, "flags", "ItemSpecialEffect", "Special effect flags", &Item::_iFlags);
LuaSetDocProperty(itemType, "miscId", "ItemMiscID", "Miscellaneous ID", &Item::_iMiscId);
LuaSetDocProperty(itemType, "spell", "SpellID", "Spell", &Item::_iSpell);
LuaSetDocProperty(itemType, "IDidx", "ItemIndex", "Base item index", &Item::IDidx);
LuaSetDocProperty(itemType, "charges", "number", "Number of charges", &Item::_iCharges);
LuaSetDocProperty(itemType, "maxCharges", "number", "Maximum charges", &Item::_iMaxCharges);
LuaSetDocProperty(itemType, "durability", "number", "Durability", &Item::_iDurability);
LuaSetDocProperty(itemType, "maxDur", "number", "Maximum durability", &Item::_iMaxDur);
LuaSetDocProperty(itemType, "PLDam", "number", "Damage % bonus", &Item::_iPLDam);
LuaSetDocProperty(itemType, "PLToHit", "number", "Chance to hit bonus", &Item::_iPLToHit);
LuaSetDocProperty(itemType, "PLAC", "number", "Armor class % bonus", &Item::_iPLAC);
LuaSetDocProperty(itemType, "PLStr", "number", "Strength bonus", &Item::_iPLStr);
LuaSetDocProperty(itemType, "PLMag", "number", "Magic bonus", &Item::_iPLMag);
LuaSetDocProperty(itemType, "PLDex", "number", "Dexterity bonus", &Item::_iPLDex);
LuaSetDocProperty(itemType, "PLVit", "number", "Vitality bonus", &Item::_iPLVit);
LuaSetDocProperty(itemType, "PLFR", "number", "Fire resistance bonus", &Item::_iPLFR);
LuaSetDocProperty(itemType, "PLLR", "number", "Lightning resistance bonus", &Item::_iPLLR);
LuaSetDocProperty(itemType, "PLMR", "number", "Magic resistance bonus", &Item::_iPLMR);
LuaSetDocProperty(itemType, "PLMana", "number", "Mana bonus", &Item::_iPLMana);
LuaSetDocProperty(itemType, "PLHP", "number", "Life bonus", &Item::_iPLHP);
LuaSetDocProperty(itemType, "PLDamMod", "number", "Damage modifier bonus", &Item::_iPLDamMod);
LuaSetDocProperty(itemType, "PLGetHit", "number", "Damage from enemies bonus", &Item::_iPLGetHit);
LuaSetDocProperty(itemType, "PLLight", "number", "Light bonus", &Item::_iPLLight);
LuaSetDocProperty(itemType, "splLvlAdd", "number", "Spell level bonus", &Item::_iSplLvlAdd);
LuaSetDocProperty(itemType, "request", "boolean", "Request flag", &Item::_iRequest);
LuaSetDocProperty(itemType, "uid", "number", "Unique item ID", &Item::_iUid);
LuaSetDocProperty(itemType, "fMinDam", "number", "Fire minimum damage", &Item::_iFMinDam);
LuaSetDocProperty(itemType, "fMaxDam", "number", "Fire maximum damage", &Item::_iFMaxDam);
LuaSetDocProperty(itemType, "lMinDam", "number", "Lightning minimum damage", &Item::_iLMinDam);
LuaSetDocProperty(itemType, "lMaxDam", "number", "Lightning maximum damage", &Item::_iLMaxDam);
LuaSetDocProperty(itemType, "PLEnAc", "number", "Damage target AC bonus", &Item::_iPLEnAc);
LuaSetDocProperty(itemType, "prePower", "ItemEffectType", "Prefix power", &Item::_iPrePower);
LuaSetDocProperty(itemType, "sufPower", "ItemEffectType", "Suffix power", &Item::_iSufPower);
LuaSetDocProperty(itemType, "vAdd1", "number", "Value addition 1", &Item::_iVAdd1);
LuaSetDocProperty(itemType, "vMult1", "number", "Value multiplier 1", &Item::_iVMult1);
LuaSetDocProperty(itemType, "vAdd2", "number", "Value addition 2", &Item::_iVAdd2);
LuaSetDocProperty(itemType, "vMult2", "number", "Value multiplier 2", &Item::_iVMult2);
LuaSetDocProperty(itemType, "minStr", "number", "Minimum strength required", &Item::_iMinStr);
LuaSetDocProperty(itemType, "minMag", "number", "Minimum magic required", &Item::_iMinMag);
LuaSetDocProperty(itemType, "minDex", "number", "Minimum dexterity required", &Item::_iMinDex);
LuaSetDocProperty(itemType, "statFlag", "boolean", "Equippable flag", &Item::_iStatFlag);
LuaSetDocProperty(itemType, "damAcFlags", "ItemSpecialEffectHf", "Secondary special effect flags", &Item::_iDamAcFlags);
LuaSetDocProperty(itemType, "buff", "number", "Secondary creation flags", &Item::dwBuff);
// Member functions
SetDocumented(itemType, "pop", "() -> Item", "Clears this item and returns the old value", &Item::pop);
SetDocumented(itemType, "clear", "() -> void", "Resets the item", &Item::clear);
SetDocumented(itemType, "isEmpty", "() -> boolean", "Checks whether this item is empty", &Item::isEmpty);
SetDocumented(itemType, "isEquipment", "() -> boolean", "Checks if item is equipment", &Item::isEquipment);
SetDocumented(itemType, "isWeapon", "() -> boolean", "Checks if item is a weapon", &Item::isWeapon);
SetDocumented(itemType, "isArmor", "() -> boolean", "Checks if item is armor", &Item::isArmor);
SetDocumented(itemType, "isGold", "() -> boolean", "Checks if item is gold", &Item::isGold);
SetDocumented(itemType, "isHelm", "() -> boolean", "Checks if item is a helm", &Item::isHelm);
SetDocumented(itemType, "isShield", "() -> boolean", "Checks if item is a shield", &Item::isShield);
SetDocumented(itemType, "isJewelry", "() -> boolean", "Checks if item is jewelry", &Item::isJewelry);
SetDocumented(itemType, "isScroll", "() -> boolean", "Checks if item is a scroll", &Item::isScroll);
SetDocumented(itemType, "isScrollOf", "(spell: SpellID) -> boolean", "Checks if item is a scroll of a given spell", &Item::isScrollOf);
SetDocumented(itemType, "isRune", "() -> boolean", "Checks if item is a rune", &Item::isRune);
SetDocumented(itemType, "isRuneOf", "(spell: SpellID) -> boolean", "Checks if item is a rune of a given spell", &Item::isRuneOf);
SetDocumented(itemType, "isUsable", "() -> boolean", "Checks if item is usable", &Item::isUsable);
SetDocumented(itemType, "keyAttributesMatch", "(seed: number, idx: number, createInfo: number) -> boolean", "Checks if key attributes match", &Item::keyAttributesMatch);
SetDocumented(itemType, "getTextColor", "() -> UiFlags", "Gets the text color", &Item::getTextColor);
SetDocumented(itemType, "getTextColorWithStatCheck", "() -> UiFlags", "Gets the text color with stat check", &Item::getTextColorWithStatCheck);
SetDocumented(itemType, "setNewAnimation", "(showAnimation: boolean) -> void", "Sets the new animation", &Item::setNewAnimation);
SetDocumented(itemType, "updateRequiredStatsCacheForPlayer", "(player: Player) -> void", "Updates the required stats cache", &Item::updateRequiredStatsCacheForPlayer);
SetDocumented(itemType, "getName", "() -> string", "Gets the translated item name", &Item::getName);
LuaSetDocFn(itemType, "pop", "() -> Item", "Clears this item and returns the old value", &Item::pop);
LuaSetDocFn(itemType, "clear", "() -> void", "Resets the item", &Item::clear);
LuaSetDocFn(itemType, "isEmpty", "() -> boolean", "Checks whether this item is empty", &Item::isEmpty);
LuaSetDocFn(itemType, "isEquipment", "() -> boolean", "Checks if item is equipment", &Item::isEquipment);
LuaSetDocFn(itemType, "isWeapon", "() -> boolean", "Checks if item is a weapon", &Item::isWeapon);
LuaSetDocFn(itemType, "isArmor", "() -> boolean", "Checks if item is armor", &Item::isArmor);
LuaSetDocFn(itemType, "isGold", "() -> boolean", "Checks if item is gold", &Item::isGold);
LuaSetDocFn(itemType, "isHelm", "() -> boolean", "Checks if item is a helm", &Item::isHelm);
LuaSetDocFn(itemType, "isShield", "() -> boolean", "Checks if item is a shield", &Item::isShield);
LuaSetDocFn(itemType, "isJewelry", "() -> boolean", "Checks if item is jewelry", &Item::isJewelry);
LuaSetDocFn(itemType, "isScroll", "() -> boolean", "Checks if item is a scroll", &Item::isScroll);
LuaSetDocFn(itemType, "isScrollOf", "(spell: SpellID) -> boolean", "Checks if item is a scroll of a given spell", &Item::isScrollOf);
LuaSetDocFn(itemType, "isRune", "() -> boolean", "Checks if item is a rune", &Item::isRune);
LuaSetDocFn(itemType, "isRuneOf", "(spell: SpellID) -> boolean", "Checks if item is a rune of a given spell", &Item::isRuneOf);
LuaSetDocFn(itemType, "isUsable", "() -> boolean", "Checks if item is usable", &Item::isUsable);
LuaSetDocFn(itemType, "keyAttributesMatch", "(seed: number, idx: number, createInfo: number) -> boolean", "Checks if key attributes match", &Item::keyAttributesMatch);
LuaSetDocFn(itemType, "getTextColor", "() -> UiFlags", "Gets the text color", &Item::getTextColor);
LuaSetDocFn(itemType, "getTextColorWithStatCheck", "() -> UiFlags", "Gets the text color with stat check", &Item::getTextColorWithStatCheck);
LuaSetDocFn(itemType, "setNewAnimation", "(showAnimation: boolean) -> void", "Sets the new animation", &Item::setNewAnimation);
LuaSetDocFn(itemType, "updateRequiredStatsCacheForPlayer", "(player: Player) -> void", "Updates the required stats cache", &Item::updateRequiredStatsCacheForPlayer);
LuaSetDocFn(itemType, "getName", "() -> string", "Gets the translated item name", &Item::getName);
}
void RegisterItemTypeEnum(sol::state_view &lua)

14
Source/lua/modules/player.cpp

@ -13,10 +13,10 @@ namespace {
void InitPlayerUserType(sol::state_view &lua)
{
sol::usertype<Player> playerType = lua.new_usertype<Player>(sol::no_constructor);
SetDocumented(playerType, "name", "",
LuaSetDocReadonlyProperty(playerType, "name", "string",
"Player's name (readonly)",
sol::readonly_property(&Player::name));
SetDocumented(playerType, "addExperience", "(experience: integer, monsterLevel: integer = nil)",
&Player::name);
LuaSetDocFn(playerType, "addExperience", "(experience: integer, monsterLevel: integer = nil)",
"Adds experience to this player based on the current game mode",
[](Player &player, uint32_t experience, std::optional<int> monsterLevel) {
if (monsterLevel.has_value()) {
@ -25,9 +25,9 @@ void InitPlayerUserType(sol::state_view &lua)
player.addExperience(experience);
}
});
SetDocumented(playerType, "characterLevel", "",
LuaSetDocProperty(playerType, "characterLevel", "number",
"Character level (writeable)",
sol::property(&Player::getCharacterLevel, &Player::setCharacterLevel));
&Player::getCharacterLevel, &Player::setCharacterLevel);
}
} // namespace
@ -35,12 +35,12 @@ sol::table LuaPlayerModule(sol::state_view &lua)
{
InitPlayerUserType(lua);
sol::table table = lua.create_table();
SetDocumented(table, "self", "()",
LuaSetDocFn(table, "self", "()",
"The current player",
[]() {
return MyPlayer;
});
SetDocumented(table, "walk_to", "(x: integer, y: integer)",
LuaSetDocFn(table, "walk_to", "(x: integer, y: integer)",
"Walk to the given coordinates",
[](int x, int y) {
NetSendCmdLoc(MyPlayerId, true, CMD_WALKXY, Point { x, y });

6
Source/lua/modules/render.cpp

@ -12,12 +12,12 @@ namespace devilution {
sol::table LuaRenderModule(sol::state_view &lua)
{
sol::table table = lua.create_table();
SetDocumented(table, "string", "(text: string, x: integer, y: integer)",
LuaSetDocFn(table, "string", "(text: string, x: integer, y: integer)",
"Renders a string at the given coordinates",
[](std::string_view text, int x, int y) { DrawString(GlobalBackBuffer(), text, { x, y }); });
SetDocumented(table, "screen_width", "()",
LuaSetDocFn(table, "screen_width", "()",
"Returns the screen width", []() { return gnScreenWidth; });
SetDocumented(table, "screen_height", "()",
LuaSetDocFn(table, "screen_height", "()",
"Returns the screen height", []() { return gnScreenHeight; });
return table;
}

4
Source/lua/modules/towners.cpp

@ -31,7 +31,7 @@ const char *const TownerTableNames[NUM_TOWNER_TYPES] {
void PopulateTownerTable(_talker_id townerId, sol::table &out)
{
SetDocumented(out, "position", "()",
LuaSetDocFn(out, "position", "()",
"Returns towner coordinates",
[townerId]() -> std::optional<std::pair<int, int>> {
const Towner *towner = GetTowner(townerId);
@ -47,7 +47,7 @@ sol::table LuaTownersModule(sol::state_view &lua)
for (uint8_t townerId = TOWN_SMITH; townerId < NUM_TOWNER_TYPES; ++townerId) {
sol::table townerTable = lua.create_table();
PopulateTownerTable(static_cast<_talker_id>(townerId), townerTable);
SetDocumented(table, TownerTableNames[townerId], /*signature=*/"", TownerLongNames[townerId], std::move(townerTable));
LuaSetDoc(table, TownerTableNames[townerId], /*signature=*/"", TownerLongNames[townerId], std::move(townerTable));
}
return table;
}

Loading…
Cancel
Save