From 1c0987115dbdf9d4b5362a3947b2ae6211dd5c4e Mon Sep 17 00:00:00 2001 From: Yuri Pourre Date: Sun, 21 Dec 2025 03:04:40 -0800 Subject: [PATCH] Expose lua methods for items and restore life and mana (#8369) --- Source/lua/modules/items.cpp | 11 ++++++ Source/lua/modules/player.cpp | 66 +++++++++++++++++++++++++++++++++++ assets/lua/repl_prelude.lua | 12 +++++++ 3 files changed, 89 insertions(+) diff --git a/Source/lua/modules/items.cpp b/Source/lua/modules/items.cpp index b84dcd80a..ec395807e 100644 --- a/Source/lua/modules/items.cpp +++ b/Source/lua/modules/items.cpp @@ -485,6 +485,17 @@ sol::table LuaItemModule(sol::state_view &lua) LuaSetDocFn(table, "addItemDataFromTsv", "(path: string, baseMappingId: number)", AddItemDataFromTsv); LuaSetDocFn(table, "addUniqueItemDataFromTsv", "(path: string, baseMappingId: number)", AddUniqueItemDataFromTsv); + // Expose enums through the module table + table["ItemIndex"] = lua["ItemIndex"]; + table["ItemType"] = lua["ItemType"]; + table["ItemClass"] = lua["ItemClass"]; + table["ItemEquipType"] = lua["ItemEquipType"]; + table["ItemMiscID"] = lua["ItemMiscID"]; + table["SpellID"] = lua["SpellID"]; + table["ItemEffectType"] = lua["ItemEffectType"]; + table["ItemSpecialEffect"] = lua["ItemSpecialEffect"]; + table["ItemSpecialEffectHf"] = lua["ItemSpecialEffectHf"]; + return table; } diff --git a/Source/lua/modules/player.cpp b/Source/lua/modules/player.cpp index 28a0e2cca..c9f8d44c6 100644 --- a/Source/lua/modules/player.cpp +++ b/Source/lua/modules/player.cpp @@ -5,11 +5,15 @@ #include #include "engine/point.hpp" +#include "engine/random.hpp" +#include "inv.h" +#include "items.h" #include "lua/metadoc.hpp" #include "player.h" namespace devilution { namespace { + void InitPlayerUserType(sol::state_view &lua) { sol::usertype playerType = lua.new_usertype(sol::no_constructor); @@ -28,6 +32,67 @@ void InitPlayerUserType(sol::state_view &lua) LuaSetDocProperty(playerType, "characterLevel", "number", "Character level (writeable)", &Player::getCharacterLevel, &Player::setCharacterLevel); + LuaSetDocFn(playerType, "addItem", "(itemId: integer, count: integer = 1)", + "Add an item to the player's inventory", + [](Player &player, int itemId, std::optional count) -> bool { + const _item_indexes itemIndex = static_cast<_item_indexes>(itemId); + const int itemCount = count.value_or(1); + for (int i = 0; i < itemCount; i++) { + Item tempItem {}; + SetupAllItems(player, tempItem, itemIndex, AdvanceRndSeed(), 1, 1, true, false); + if (!AutoPlaceItemInInventory(player, tempItem, true)) { + return false; + } + } + CalcPlrInv(player, true); + return true; + }); + LuaSetDocFn(playerType, "hasItem", "(itemId: integer)", + "Check if the player has an item with the given ID", + [](const Player &player, int itemId) -> bool { + return HasInventoryOrBeltItemWithId(player, static_cast<_item_indexes>(itemId)); + }); + LuaSetDocFn(playerType, "removeItem", "(itemId: integer, count: integer = 1)", + "Remove an item from the player's inventory", + [](Player &player, int itemId, std::optional count) -> int { + const _item_indexes targetId = static_cast<_item_indexes>(itemId); + const int itemCount = count.value_or(1); + int removed = 0; + + // Remove from inventory + for (int i = player._pNumInv - 1; i >= 0 && removed < itemCount; i--) { + if (player.InvList[i].IDidx == targetId) { + player.RemoveInvItem(i); + removed++; + } + } + + // Remove from belt if needed + for (int i = MaxBeltItems - 1; i >= 0 && removed < itemCount; i--) { + if (!player.SpdList[i].isEmpty() && player.SpdList[i].IDidx == targetId) { + player.RemoveSpdBarItem(i); + removed++; + } + } + + if (removed > 0) { + CalcPlrInv(player, true); + } + + return removed; + }); + LuaSetDocFn(playerType, "restoreFullLife", "()", + "Restore player's HP to maximum", + [](Player &player) { + player._pHitPoints = player._pMaxHP; + player._pHPBase = player._pMaxHPBase; + }); + LuaSetDocFn(playerType, "restoreFullMana", "()", + "Restore player's mana to maximum", + [](Player &player) { + player._pMana = player._pMaxMana; + player._pManaBase = player._pMaxManaBase; + }); } } // namespace @@ -45,6 +110,7 @@ sol::table LuaPlayerModule(sol::state_view &lua) [](int x, int y) { NetSendCmdLoc(MyPlayerId, true, CMD_WALKXY, Point { x, y }); }); + return table; } diff --git a/assets/lua/repl_prelude.lua b/assets/lua/repl_prelude.lua index b871affbc..f58aabb1a 100644 --- a/assets/lua/repl_prelude.lua +++ b/assets/lua/repl_prelude.lua @@ -1,5 +1,6 @@ events = require('devilutionx.events') i18n = require('devilutionx.i18n') +items = require('devilutionx.items') log = require('devilutionx.log') audio = require('devilutionx.audio') player = require('devilutionx.player') @@ -8,3 +9,14 @@ towners = require('devilutionx.towners') message = require('devilutionx.message') if _DEBUG then dev = require('devilutionx.dev') end inspect = require('inspect') + +-- Expose item enums from items module for easy access in console +ItemIndex = items.ItemIndex +ItemType = items.ItemType +ItemClass = items.ItemClass +ItemEquipType = items.ItemEquipType +ItemMiscID = items.ItemMiscID +SpellID = items.SpellID +ItemEffectType = items.ItemEffectType +ItemSpecialEffect = items.ItemSpecialEffect +ItemSpecialEffectHf = items.ItemSpecialEffectHf