You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

127 lines
4.2 KiB

#include "lua/modules/player.hpp"
#include <optional>
#include <sol/sol.hpp>
#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<Player> playerType = lua.new_usertype<Player>(sol::no_constructor);
LuaSetDocReadonlyProperty(playerType, "name", "string",
"Player's name (readonly)",
&Player::name);
LuaSetDocReadonlyProperty(playerType, "id", "integer",
"Player's unique ID (readonly)",
[](const Player &player) {
return static_cast<int>(reinterpret_cast<uintptr_t>(&player));
});
LuaSetDocReadonlyProperty(playerType, "position", "Point",
"Player's current position (readonly)",
[](const Player &player) -> Point {
return Point { player.position.tile };
});
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()) {
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<int> 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<int> 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