Skip to content

Commit 3e2aaf2

Browse files
authoredJan 25, 2023
fix: imbuement decay time (#818)
Now the time decay logic of the imbuements is working as it should: • Backpacks imbuements will only decay if equipped in the backpack slot; • Normal item will only decay if in battle mode and out of protection zone, as well as in global.
1 parent 107138d commit 3e2aaf2

File tree

12 files changed

+51
-72
lines changed

12 files changed

+51
-72
lines changed
 

‎src/creatures/players/imbuements/imbuements.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ bool Imbuements::loadFromXml(bool /* reloading */) {
5151
pugi::cast<uint32_t>(baseNode.attribute("price").value()),
5252
pugi::cast<uint32_t>(baseNode.attribute("protectionPrice").value()),
5353
pugi::cast<uint32_t>(baseNode.attribute("removecost").value()),
54-
pugi::cast<int32_t>(baseNode.attribute("duration").value()),
54+
pugi::cast<uint32_t>(baseNode.attribute("duration").value()),
5555
pugi::cast<uint16_t>(baseNode.attribute("percent").value())
5656

5757
);

‎src/creatures/players/imbuements/imbuements.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ class Item;
2020
class Imbuement;
2121

2222
struct BaseImbuement {
23-
BaseImbuement(uint16_t initId, std::string initName, uint32_t initProtectionPrice, uint32_t initPrice, uint32_t initRemoveCost, int32_t initDuration, uint8_t initPercent) :
23+
BaseImbuement(uint16_t initId, std::string initName, uint32_t initProtectionPrice, uint32_t initPrice, uint32_t initRemoveCost, uint32_t initDuration, uint8_t initPercent) :
2424
id(initId), name(std::move(initName)), protectionPrice(initProtectionPrice), price(initPrice), removeCost(initRemoveCost), duration(initDuration), percent(initPercent) {}
2525

2626
uint16_t id;
2727
std::string name;
2828
uint32_t protectionPrice;
2929
uint32_t price;
3030
uint32_t removeCost;
31-
int32_t duration;
31+
uint32_t duration;
3232
uint8_t percent;
3333
};
3434

‎src/creatures/players/player.cpp

+33-22
Original file line numberDiff line numberDiff line change
@@ -462,45 +462,57 @@ void Player::updateInventoryWeight()
462462
}
463463
}
464464

465-
void Player::updateInventoryImbuement(bool init /* = false */)
465+
void Player::updateInventoryImbuement()
466466
{
467+
// Get the tile the player is currently on
467468
const Tile* playerTile = getTile();
469+
// Check if the player is in a protection zone
468470
bool isInProtectionZone = playerTile && playerTile->hasFlag(TILESTATE_PROTECTIONZONE);
471+
// Check if the player is in fight mode
469472
bool isInFightMode = hasCondition(CONDITION_INFIGHT);
470-
471-
uint8_t imbuementsToCheck = g_game().getPlayerActiveImbuements(getID());
472-
for (auto item : getAllInventoryItems()) {
473+
// Iterate through all items in the player's inventory
474+
for (auto item : getAllInventoryItems())
475+
{
476+
// Iterate through all imbuement slots on the item
473477
for (uint8_t slotid = 0; slotid < item->getImbuementSlot(); slotid++)
474478
{
475479
ImbuementInfo imbuementInfo;
480+
// Get the imbuement information for the current slot
476481
if (!item->getImbuementInfo(slotid, &imbuementInfo))
477482
{
478-
continue;
483+
// If no imbuement is found, continue to the next slot
484+
break;
479485
}
480486

481-
const CategoryImbuement* categoryImbuement = g_imbuements().getCategoryByID(imbuementInfo.imbuement->getCategory());
482-
if (categoryImbuement && categoryImbuement->agressive)
483-
{
484-
if (isInProtectionZone || !isInFightMode)
485-
{
486-
break;
487+
// Imbuement from imbuementInfo, this variable reduces code complexity
488+
auto imbuement = imbuementInfo.imbuement;
489+
// Get the category of the imbuement
490+
const CategoryImbuement* categoryImbuement = g_imbuements().getCategoryByID(imbuement->getCategory());
491+
// Parent of the imbued item
492+
auto parent = item->getParent();
493+
// If the imbuement is aggressive and the player is not in fight mode or is in a protection zone, or the item is in a container, ignore it.
494+
if (categoryImbuement && categoryImbuement->agressive) {
495+
if (!isInFightMode || isInProtectionZone || parent && parent->getContainer()) {
496+
continue;
487497
}
488498
}
489-
490-
if (init)
491-
{
492-
g_game().increasePlayerActiveImbuements(getID());
499+
// If the item is not in the backpack slot and it's not a agressive imbuement, ignore it.
500+
if (categoryImbuement && !categoryImbuement->agressive && parent && parent != this) {
501+
continue;
493502
}
494503

495-
int32_t duration = std::max<int32_t>(0, imbuementInfo.duration - EVENT_IMBUEMENT_INTERVAL / 1000);
496-
item->decayImbuementTime(slotid, imbuementInfo.imbuement->getID(), duration);
497-
if (duration == 0)
504+
// If the imbuement's duration is 0, remove its stats and continue to the next slot
505+
if (imbuementInfo.duration == 0)
498506
{
499-
removeItemImbuementStats(imbuementInfo.imbuement);
500-
g_game().decreasePlayerActiveImbuements(getID());
507+
removeItemImbuementStats(imbuement);
508+
continue;
501509
}
502510

503-
imbuementsToCheck--;
511+
SPDLOG_DEBUG("Decaying imbuement {} from item {} of player {}", imbuement->getName(), item->getName(), getName());
512+
// Calculate the new duration of the imbuement, making sure it doesn't go below 0
513+
uint64_t duration = std::max<uint64_t>(0, imbuementInfo.duration - EVENT_IMBUEMENT_INTERVAL / 1000);
514+
// Update the imbuement's duration in the item
515+
item->decayImbuementTime(slotid, imbuement->getID(), duration);
504516
}
505517
}
506518
}
@@ -1287,7 +1299,6 @@ void Player::onApplyImbuement(Imbuement *imbuement, Item *item, uint8_t slot, bo
12871299

12881300
item->addImbuement(slot, imbuement->getID(), baseImbuement->duration);
12891301
openImbuementWindow(item);
1290-
updateInventoryImbuement();
12911302
}
12921303

12931304
void Player::onClearImbuement(Item* item, uint8_t slot)

‎src/creatures/players/player.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -2198,7 +2198,7 @@ class Player final : public Creature, public Cylinder
21982198
* @brief Starts checking the imbuements in the item so that the time decay is performed
21992199
* Registers the player in an unordered_map in game.h so that the function can be initialized by the task
22002200
*/
2201-
void updateInventoryImbuement(bool init = false);
2201+
void updateInventoryImbuement();
22022202

22032203
void setNextWalkActionTask(SchedulerTask* task);
22042204
void setNextWalkTask(SchedulerTask* task);

‎src/game/game.cpp

+3-9
Original file line numberDiff line numberDiff line change
@@ -6513,18 +6513,12 @@ void Game::checkImbuements()
65136513

65146514
std::vector<uint32_t> toErase;
65156515

6516-
for (const auto& [key, value] : playersActiveImbuements) {
6517-
Player* player = getPlayerByID(key);
6518-
if (!player) {
6519-
toErase.push_back(key);
6516+
for (const auto& [mapPlayerId, mapPlayer] : getPlayers()) {
6517+
if (!mapPlayer) {
65206518
continue;
65216519
}
65226520

6523-
player->updateInventoryImbuement();
6524-
}
6525-
6526-
for (uint32_t playerId : toErase) {
6527-
setPlayerActiveImbuements(playerId, 0);
6521+
mapPlayer->updateInventoryImbuement();
65286522
}
65296523

65306524
}

‎src/game/game.h

-22
Original file line numberDiff line numberDiff line change
@@ -537,27 +537,6 @@ class Game
537537
return CharmList;
538538
}
539539

540-
void increasePlayerActiveImbuements(uint32_t playerId) {
541-
setPlayerActiveImbuements(playerId, playersActiveImbuements[playerId] + 1);
542-
}
543-
544-
void decreasePlayerActiveImbuements(uint32_t playerId) {
545-
setPlayerActiveImbuements(playerId, playersActiveImbuements[playerId] - 1);
546-
}
547-
548-
void setPlayerActiveImbuements(uint32_t playerId, uint8_t value) {
549-
if (value <= 0) {
550-
playersActiveImbuements.erase(playerId);
551-
return;
552-
}
553-
554-
playersActiveImbuements[playerId] = std::min<uint8_t>(255, value);
555-
}
556-
557-
uint8_t getPlayerActiveImbuements(uint32_t playerId) {
558-
return playersActiveImbuements[playerId];
559-
}
560-
561540
FILELOADER_ERRORS loadAppearanceProtobuf(const std::string& file);
562541
bool isMagicEffectRegistered(uint8_t type) const {
563542
return std::find(registeredMagicEffects.begin(), registeredMagicEffects.end(), type) != registeredMagicEffects.end();
@@ -609,7 +588,6 @@ class Game
609588
void playerSpeakToNpc(Player* player, const std::string& text);
610589

611590
phmap::flat_hash_map<uint32_t, Player*> players;
612-
phmap::flat_hash_map<uint32_t, uint8_t> playersActiveImbuements;
613591
phmap::flat_hash_map<std::string, Player*> mappedPlayerNames;
614592
phmap::flat_hash_map<uint32_t, Guild*> guilds;
615593
phmap::flat_hash_map<uint16_t, Item*> uniqueItems;

‎src/io/iologindata.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,6 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
734734
player->initializeTaskHunting();
735735
player->updateBaseSpeed();
736736
player->updateInventoryWeight();
737-
player->updateInventoryImbuement(true);
738737
player->updateItemsLight(true);
739738
return true;
740739
}

‎src/items/item.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,16 @@ bool Item::getImbuementInfo(uint8_t slot, ImbuementInfo *imbuementInfo)
8383
return imbuementInfo->duration && imbuementInfo->imbuement;
8484
}
8585

86-
void Item::setImbuement(uint8_t slot, uint16_t imbuementId, int32_t duration)
86+
void Item::setImbuement(uint8_t slot, uint16_t imbuementId, uint32_t duration)
8787
{
8888
std::string key = std::to_string(IMBUEMENT_SLOT + slot);
8989
ItemAttributes::CustomAttribute customAttribute;
90-
customAttribute.setInt64(duration > 0 ? (duration << 8) | imbuementId : 0);
90+
auto convertSafeValue = std::clamp(static_cast<int64_t>(duration), (int64_t)0, std::numeric_limits<int64_t>::max());
91+
customAttribute.setInt64(convertSafeValue > 0 ? (convertSafeValue << 8) | imbuementId : 0);
9192
setCustomAttribute(key, customAttribute);
9293
}
9394

94-
void Item::addImbuement(uint8_t slot, uint16_t imbuementId, int32_t duration)
95+
void Item::addImbuement(uint8_t slot, uint16_t imbuementId, uint32_t duration)
9596
{
9697
Player* player = getHoldingPlayer();
9798
if (!player) {
@@ -1493,8 +1494,8 @@ std::string Item::parseImbuementDescription(const Item* item)
14931494
continue;
14941495
}
14951496

1496-
int minutes = imbuementInfo.duration / 60;
1497-
int hours = minutes / 60;
1497+
auto minutes = imbuementInfo.duration / 60;
1498+
auto hours = minutes / 60;
14981499
s << fmt::format("{} {} {:02}:{:02}h", baseImbuement->name, imbuementInfo.imbuement->getName(), hours, minutes % 60);
14991500
}
15001501
s << ").";

‎src/items/item.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -1049,15 +1049,15 @@ class Item : virtual public Thing
10491049
* @return false
10501050
*/
10511051
bool getImbuementInfo(uint8_t slot, ImbuementInfo *imbuementInfo);
1052-
void addImbuement(uint8_t slot, uint16_t imbuementId, int32_t duration);
1052+
void addImbuement(uint8_t slot, uint16_t imbuementId, uint32_t duration);
10531053
/**
10541054
* @brief Decay imbuement time duration, only use this for decay the imbuement time
10551055
*
10561056
* @param slot Slot id to decay
10571057
* @param imbuementId Imbuement id to decay
10581058
* @param duration New duration
10591059
*/
1060-
void decayImbuementTime(uint8_t slot, uint16_t imbuementId, int32_t duration) {
1060+
void decayImbuementTime(uint8_t slot, uint16_t imbuementId, uint32_t duration) {
10611061
return setImbuement(slot, imbuementId, duration);
10621062
}
10631063
void clearImbuement(uint8_t slot, uint16_t imbuementId) {
@@ -1146,7 +1146,7 @@ class Item : virtual public Thing
11461146
bool isLootTrackeable = false;
11471147

11481148
private:
1149-
void setImbuement(uint8_t slot, uint16_t imbuementId, int32_t duration);
1149+
void setImbuement(uint8_t slot, uint16_t imbuementId, uint32_t duration);
11501150
//Don't add variables here, use the ItemAttribute class.
11511151
friend class Decay;
11521152
};

‎src/items/items_definitions.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ enum ItemParseAttributes_t {
491491

492492
struct ImbuementInfo {
493493
Imbuement *imbuement;
494-
int32_t duration = 0;
494+
uint32_t duration = 0;
495495
};
496496

497497
#endif // SRC_ITEMS_ITEMS_DEFINITIONS_HPP_

‎src/lua/creature/movement.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,6 @@ uint32_t MoveEvent::EquipItem(MoveEvent *moveEvent, Player* player, Item* item,
487487
}
488488

489489
player->addItemImbuementStats(imbuementInfo.imbuement);
490-
g_game().increasePlayerActiveImbuements(player->getID());
491-
player->updateInventoryImbuement(true);
492490
}
493491

494492
if (it.abilities) {
@@ -585,8 +583,6 @@ uint32_t MoveEvent::DeEquipItem(MoveEvent*, Player* player, Item* item, Slots_t
585583
}
586584

587585
player->removeItemImbuementStats(imbuementInfo.imbuement);
588-
g_game().decreasePlayerActiveImbuements(player->getID());
589-
player->updateInventoryImbuement(true);
590586
}
591587

592588
if (it.abilities) {

‎src/lua/functions/items/item_functions.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ int ItemFunctions::luaItemGetImbuement(lua_State* L)
769769
lua_createtable(L, 0, 3);
770770
setField(L, "id", imbuement->getID());
771771
setField(L, "name", imbuement->getName());
772-
setField(L, "duration", imbuementInfo.duration);
772+
setField(L, "duration", static_cast<lua_Number>(imbuementInfo.duration));
773773
}
774774
return 1;
775775
}

0 commit comments

Comments
 (0)