#include "lua/modules/player.hpp" #include #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); LuaSetDocReadonlyProperty(playerType, "name", "string", "Player's name (readonly)", &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 monsterLevel) { if (monsterLevel.has_value()) { player.addExperience(experience, *monsterLevel); } else { player.addExperience(experience); } }); 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 sol::table LuaPlayerModule(sol::state_view &lua) { InitPlayerUserType(lua); sol::table table = lua.create_table(); LuaSetDocFn(table, "self", "()", "The current player", []() { return MyPlayer; }); 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 }); }); return table; } } // namespace devilution