Skip to content

Commit

Permalink
Added a new method to register scripts by the map position and rework…
Browse files Browse the repository at this point in the history
… on "registerLuaEvent" function (#317)

With this modification, we can register action scripts without needing the action id/unique id or the item being on the map, as there is also a second parameter that creates the item (if it doesn't exist).

* Added a small example script on how to use record mode by position (worldboard.lua)
* A rework was performed on the "registerLuaEvent" function
* New functions were created to improve the understanding and reading of the function code.

Fixed somes bugs related to loading maps:
* Added a "try/catch" to check if the map was loaded correctly (sending an error message if there is a problem, such as the wrongly named file or not found);
* Added a boolean value "mainMap" so that some functions are only executed when loading the main map, avoiding duplications or errors.

Being that: it was divided into four smaller functions;

registerLuaItemEvent(event);
registerLuaUniqueEvent(event);
registerLuaActionEvent(event);
registerLuaPositionEvent(event);

Simple example of use:
action:position({x = 4998, y = 5000, z = 7}, 19236)

Small explanation: 
* The position parameter is obviously mandatory, the item id/name parameter is not mandatory, it can be used to create an item on the map without needing to edit the map, for scripts that need to check the id of the item inside them. 

Important notes:
* If the item already exists in the position, a warning will be sent informing that the item already exists and cannot be created, this warning will only disappear if the id/name parameter is removed.
* If the item doesn't exist (ie it's a wrong id or name), then the distro will tell you that the item is invalid.

See our wiki page for more informations: https://github.com/opentibiabr/canary/wiki/revscriptsys
  • Loading branch information
dudantas authored Apr 22, 2022
1 parent c02a492 commit a7e6426
Show file tree
Hide file tree
Showing 16 changed files with 436 additions and 121 deletions.
40 changes: 40 additions & 0 deletions data/scripts/actions/worldboard.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
local communicates = {
"Welcome to Canary Server! Visit the organization to see all our work: https://github.com/opentibiabr",
"Did you like it? Help support what we do here with a donation by visiting the link: https://docs.opentibiabr.org/donate/",
"Visit our discord to ask questions or report issues: https://discord.com/invite/3NxYnyV"
}

local scriptConfig = {
itemId = 19236,
registerPositions = {
{x = 4998, y = 5000, z = 7},
{x = 4971, y = 5300, z = 5},
{x = 4802, y = 5088, z = 7},
{x = 5518, y = 5126, z = 6},
{x = 5852, y = 5295, z = 5},
{x = 1940, y = 1345, z = 7},
{x = 4709, y = 4186, z = 7}
}
}

local worldBoard = Action()

function worldBoard.onUse(player, item, fromPosition, target, toPosition, isHotkey)
-- If the item id is not the one on the worldboard, it will return here
if item:getId() ~= scriptConfig.itemId then
return false
end

for index, value in pairs(communicates) do
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, value)
end
return true
end

-- Usage: action:position(position, itemId)
-- Explanation: The variable "item id" is optional, the id or the name of the item can be added, the item will be created in the map if it does not exist. If it already exists on the map, it will send a warning informing (in the distro) so the id must be removed so that the warning disappears keeping only the position)
for index, value in pairs(scriptConfig.registerPositions) do
worldBoard:position(value, scriptConfig.itemId)
end

worldBoard:register()
2 changes: 1 addition & 1 deletion src/creatures/combat/spells.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ bool Spell::configureSpell(const pugi::xml_node& node)
vocSpellMap[vocationId] = !attr || attr.as_bool();
} else {
SPDLOG_WARN("[Spell::configureSpell] - "
"Wrong vocation name: {]", attr.as_string());
"Wrong vocation name: {}", attr.as_string());
}
}
return true;
Expand Down
31 changes: 29 additions & 2 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ bool Game::loadMainMap(const std::string& filename)
{
Monster::despawnRange = g_configManager().getNumber(DEFAULT_DESPAWNRANGE);
Monster::despawnRadius = g_configManager().getNumber(DEFAULT_DESPAWNRADIUS);
return map.loadMap("data/world/" + filename + ".otbm", true, true, true);
return map.loadMap("data/world/" + filename + ".otbm", true, true, true, true);
}

bool Game::loadCustomMap(const std::string& filename)
Expand All @@ -681,7 +681,7 @@ bool Game::loadCustomMap(const std::string& filename)

void Game::loadMap(const std::string& path)
{
map.loadMap(path, false, false, false);
map.loadMap(path);
}

Cylinder* Game::internalGetCylinder(Player* player, const Position& pos) const
Expand Down Expand Up @@ -8691,3 +8691,30 @@ bool Game::hasDistanceEffect(uint8_t effectId) {
}
return false;
}

void Game::createLuaItemsOnMap() {
for (auto const [position, itemId] : mapLuaItemsStored) {
Item* item = Item::CreateItem(itemId, 1);
if (!item) {
SPDLOG_WARN("[Game::createLuaItemsOnMap] - Cannot create item with id {}", itemId);
continue;
}

if (position.x != 0) {
Tile* tile = g_game().map.getTile(position);
if (!tile) {
SPDLOG_WARN("[Game::createLuaItemsOnMap] - Tile is wrong or not found position: {}", position.toString());
delete item;
continue;
}

// If the item already exists on the map, then ignore it and send warning
if (g_game().findItemOfType(tile, itemId, false, -1)) {
SPDLOG_WARN("[Game::createLuaItemsOnMap] - Cannot create item with id {} on position {}, item already exists", itemId, position.toString());
continue;
}

g_game().internalAddItem(tile, item, INDEX_WHEREEVER, FLAG_NOLIMIT);
}
}
}
12 changes: 12 additions & 0 deletions src/game/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ class Game
Item* findItemOfType(Cylinder* cylinder, uint16_t itemId,
bool depthSearch = true, int32_t subType = -1) const;

void createLuaItemsOnMap();

bool removeMoney(Cylinder* cylinder, uint64_t money,
uint32_t flags = 0, bool useBank = false);

Expand Down Expand Up @@ -568,6 +570,10 @@ class Game
return playersActiveImbuements[playerId];
}

void setCreateLuaItems(Position position, uint16_t itemId) {
mapLuaItemsStored[position] = itemId;
}

private:
void checkImbuements();
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
Expand All @@ -583,6 +589,12 @@ class Game
std::unordered_map<uint16_t, Item*> uniqueItems;
std::map<uint32_t, uint32_t> stages;

/* Items stored from the lua scripts positions
* For example: ActionFunctions::luaActionPosition
* This basically works so that the item is created after the map is loaded, because the scripts are loaded before the map is loaded, we will use this table to create items that don't exist in the map natively through each script
*/
std::map<Position, uint16_t> mapLuaItemsStored;

std::map<uint16_t, std::string> BestiaryList;
std::string boostedCreature = "";

Expand Down
8 changes: 8 additions & 0 deletions src/items/items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,14 @@ const ItemType& Items::getItemType(size_t id) const
return items.front();
}

bool Items::hasItemType(size_t hasId) const
{
if (hasId < items.size()) {
return true;
}
return false;
}

const ItemType& Items::getItemIdByClientId(uint16_t spriteId) const
{
auto it = reverseItemMap.find(spriteId);
Expand Down
9 changes: 9 additions & 0 deletions src/items/items.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,15 @@ class Items
ItemType& getItemType(size_t id);
const ItemType& getItemIdByClientId(uint16_t spriteId) const;

/**
* @brief Check if the itemid "hasId" is stored on "items", if not, return false
*
* @param hasId check item id
* @return true if the item exist
* @return false if the item not exist
*/
bool hasItemType(size_t hasId) const;

uint16_t getItemIdByName(const std::string& name);

ItemTypes_t getLootType(const std::string& strValue);
Expand Down
195 changes: 129 additions & 66 deletions src/lua/creature/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ void Actions::clear(bool fromLua) {
clearMap(uniqueItemMap, fromLua);
clearMap(actionItemMap, fromLua);

// Clear position map
for (auto it = actionPositionMap.begin(); it != actionPositionMap.end(); ) {
if (fromLua == it->second.fromLua) {
it = actionPositionMap.erase(it);
} else {
++it;
}
}

reInitState(fromLua);
}

Expand Down Expand Up @@ -199,79 +208,116 @@ bool Actions::registerEvent(Event_ptr event, const pugi::xml_node& node) {
return false;
}

bool Actions::registerLuaEvent(Action* event) {
Action_ptr action{ event };
if (action->getItemIdRange().size() > 0) {
if (action->getItemIdRange().size() == 1) {
auto result = useItemMap.emplace(action->getItemIdRange().at(0), std::move(*action));
if (!result.second) {
SPDLOG_WARN("[Actions::registerLuaEvent] - Duplicate "
"registered item with id: {}",
action->getItemIdRange().at(0));
}
return result.second;
} else {
auto v = action->getItemIdRange();
for (auto i = v.begin(); i != v.end(); i++) {
auto result = useItemMap.emplace(*i, std::move(*action));
if (!result.second) {
SPDLOG_WARN("[Actions::registerLuaEvent] - Duplicate "
"registered item with id: {} in range from id: {}, to id: {}",
*i, v.at(0), v.at(v.size() - 1));
continue;
}
}
return true;
bool Actions::registerLuaItemEvent(Action* action) {
auto itemIdVector = action->getItemIdsVector();
if (itemIdVector.empty()) {
return false;
}

std::for_each(itemIdVector.begin(), itemIdVector.end(), [this, &action, &itemIdVector](uint16_t &itemId) {
// Check if the item is already registered and prevent it from being registered again
if (hasItemId(itemId)) {
SPDLOG_WARN("[Actions::registerLuaItemEvent] - Duplicate "
"registered item with id: {} in range from id: {}, to id: {}",
itemId, itemIdVector.at(0), itemIdVector.at(itemIdVector.size() - 1));
return false;
}
} else if (action->getUniqueIdRange().size() > 0) {
if (action->getUniqueIdRange().size() == 1) {
auto result = uniqueItemMap.emplace(action->getUniqueIdRange().at(0), std::move(*action));
if (!result.second) {
SPDLOG_WARN("[Actions::registerLuaEvent] - Duplicate "
"registered item with uid: {}",
action->getUniqueIdRange().at(0));
}
return result.second;
} else {
auto v = action->getUniqueIdRange();
for (auto i = v.begin(); i != v.end(); i++) {
auto result = uniqueItemMap.emplace(*i, std::move(*action));
if (!result.second) {
SPDLOG_WARN("[Actions::registerLuaEvent] - Duplicate "
"registered item with uid: {} in range from uid: {}, to uid: {}",
*i, v.at(0), v.at(v.size() - 1));
continue;
}
}
return true;

// Register item in the action item map
setItemId(itemId, std::move(*action));
return true;
});
itemIdVector.clear();
itemIdVector.shrink_to_fit();
return true;
}

bool Actions::registerLuaUniqueEvent(Action* action) {
auto uniqueIdVector = action->getUniqueIdsVector();
if (uniqueIdVector.empty()) {
return false;
}

std::for_each(uniqueIdVector.begin(), uniqueIdVector.end(), [this, &action, &uniqueIdVector](uint16_t &uniqueId) {
// Check if the unique is already registered and prevent it from being registered again
if (hasUniqueId(uniqueId)) {
SPDLOG_WARN("[Actions::registerLuaUniqueEvent] - Duplicate "
"registered item with uid: {} in range from uid: {}, to uid: {}",
uniqueId, uniqueIdVector.at(0), uniqueIdVector.at(uniqueIdVector.size() - 1));
return false;
}
} else if (action->getActionIdRange().size() > 0) {
if (action->getActionIdRange().size() == 1) {
auto result = actionItemMap.emplace(action->getActionIdRange().at(0), std::move(*action));
if (!result.second) {
SPDLOG_WARN("[Actions::registerLuaEvent] - Duplicate "
"registered item with aid: {}",
action->getActionIdRange().at(0));
}
return result.second;
} else {
auto v = action->getActionIdRange();
for (auto i = v.begin(); i != v.end(); i++) {
auto result = actionItemMap.emplace(*i, std::move(*action));
if (!result.second) {
SPDLOG_WARN("[Actions::registerLuaEvent] Duplicate "
"registered item with aid: {} in range from aid: {}, to aid: {}",
*i, v.at(0), v.at(v.size() - 1));
continue;
}
}
return true;

// Register unique id the unique item map
setUniqueId(uniqueId, std::move(*action));
return true;
});

uniqueIdVector.clear();
uniqueIdVector.shrink_to_fit();
return true;
}

bool Actions::registerLuaActionEvent(Action* action) {
auto actionIdVector = action->getActionIdsVector();
if (actionIdVector.empty()) {
return false;
}

std::for_each(actionIdVector.begin(), actionIdVector.end(), [this, &action, &actionIdVector](uint16_t &actionId) {
// Check if the unique is already registered and prevent it from being registered again
if (hasActionId(actionId)) {
SPDLOG_WARN("[Actions::registerLuaActionEvent] - Duplicate "
"registered item with aid: {} in range from aid: {}, to aid: {}",
actionId, actionIdVector.at(0), actionIdVector.at(actionIdVector.size() - 1));
return false;
}

// Register action in the action item map
setActionId(actionId, std::move(*action));
return true;
});

actionIdVector.clear();
actionIdVector.shrink_to_fit();
return true;
}

bool Actions::registerLuaPositionEvent(Action* action) {
auto positionVector = action->getPositionsVector();
if (positionVector.empty()) {
return false;
}

for (Position position : positionVector) {
// Check if the position is already registered and prevent it from being registered again
if (hasPosition(position)) {
SPDLOG_WARN("[Actions::registerLuaPositionEvent] - Duplicate "
"registered script with range position: {}", position.toString());
continue;
}

// Register position in the action position map
setPosition(position, std::move(*action));
}

positionVector.clear();
positionVector.shrink_to_fit();
return true;
}

bool Actions::registerLuaEvent(Action* event) {
Action_ptr action{ event };

// Call all register lua events
if (registerLuaItemEvent(event) || registerLuaUniqueEvent(event) || registerLuaActionEvent(event) || registerLuaPositionEvent(event)) {
return true;
} else {
SPDLOG_WARN("[Actions::registerLuaEvent] - "
"There is no id/aid/uid set for this event");
"Missing id/aid/uid/position for one script event");
return false;
}
SPDLOG_DEBUG("[Actions::registerLuaEvent] - Missing or incorrect script event");
return false;
}

ReturnValue Actions::canUse(const Player* player, const Position& pos) {
Expand Down Expand Up @@ -339,6 +385,23 @@ Action* Actions::getAction(const Item* item) {
return &it->second;
}

if (const Tile * tile = item->getTile();
tile)
{
if (const Player* player = item->getHoldingPlayer();
player && item->getTopParent() == player)
{
SPDLOG_DEBUG("[Actions::getAction] - The position only is valid for use item in the map, player name {}", player->getName());
return nullptr;
}

if (auto iteratePositions = actionPositionMap.find(tile->getPosition());
iteratePositions != actionPositionMap.end())
{
return &iteratePositions->second;
}
}

//rune items
return g_spells->getRuneSpell(item->getID());
}
Expand Down
Loading

0 comments on commit a7e6426

Please sign in to comment.