From 4dd2f1b3faf133fa618af13b52ca81437d238026 Mon Sep 17 00:00:00 2001 From: codinablack Date: Sun, 1 Dec 2024 06:42:45 -0600 Subject: [PATCH] Adjustments to Monster::death for Reward System -Switched to using game::internalAddItem -Reduced code duplication -Improved Readability -Added error reporting to output stream for failure to add items. --- src/monster.cpp | 167 +++++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 94 deletions(-) diff --git a/src/monster.cpp b/src/monster.cpp index 09b23251..91706058 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1842,118 +1842,97 @@ bool Monster::canWalkTo(Position pos, Direction direction) const void Monster::death(Creature*) { - + auto monsterId = getID(); + auto it = g_game.rewardBossTracking.find(monsterId); // rewardboss - if (getMonster()->isRewardBoss()) { - uint32_t monsterId = getMonster()->getID(); - auto& rewardBossContributionInfo = g_game.rewardBossTracking; - - auto it = rewardBossContributionInfo.find(monsterId); - if (it == rewardBossContributionInfo.end()) return; - - auto& scoreInfo = it->second; - - uint32_t mostScoreContributor = 0; - int32_t highestScore = 0; - int32_t totalScore = 0; - int32_t contributors = 0; - int32_t totalDamageDone = 0; - int32_t totalDamageTaken = 0; - int32_t totalHealingDone = 0; - - for (const auto& [playerId, scoreInfo] : scoreInfo.playerScoreTable) { - int32_t playerScore = scoreInfo.damageDone + scoreInfo.damageTaken + scoreInfo.healingDone; - totalScore += playerScore; - totalDamageDone += scoreInfo.damageDone; - totalDamageTaken += scoreInfo.damageTaken; - totalHealingDone += scoreInfo.healingDone; - contributors++; - - if (playerScore > highestScore) { - highestScore = playerScore; - mostScoreContributor = playerId; - } - } - - const auto& creatureLoot = mType->info.lootItems; - int64_t currentTime = time(nullptr); - - for (const auto& [playerId, scoreInfo] : rewardBossContributionInfo[monsterId].playerScoreTable) { - double damageDone = scoreInfo.damageDone; - double damageTaken = scoreInfo.damageTaken; - double healingDone = scoreInfo.healingDone; - - // Base loot rate calculation with zero checks - double contrubutionScore = 0; - if (damageDone > 0) { - contrubutionScore += damageDone; - } - if (damageTaken > 0) { - contrubutionScore += damageTaken; - } - if (healingDone > 0) { - contrubutionScore += healingDone; + if (it != g_game.rewardBossTracking.end()) { + if (isRewardBoss()) { + auto& bossScoreTable = it->second; + uint32_t topContributerId = 0; + int32_t topScore = 0; + int32_t totalScore = 0; + int32_t totalDamageDone = 0; + int32_t totalDamageTaken = 0; + int32_t totalHealingDone = 0; + + for (const auto& [playerId, score] : bossScoreTable.playerScoreTable) { + int32_t playerScore = score.damageDone + score.damageTaken + score.healingDone; + totalScore += playerScore; + totalDamageDone += score.damageDone; + totalDamageTaken += score.damageTaken; + totalHealingDone += score.healingDone; + + if (playerScore > topScore) { + topScore = playerScore; + topContributerId = playerId; + } } - double expectedScore = ((contrubutionScore / totalScore) * g_config.getFloat(ConfigManager::REWARD_BASE_RATE)); - double lootRate = std::min(expectedScore, 1.0); + const auto& creatureLoot = mType->info.lootItems; + int64_t currentTime = time(nullptr); + + for (const auto& [playerId, score] : bossScoreTable.playerScoreTable) + { + auto contrubutionScore = score.damageDone + score.damageTaken + score.healingDone; + double expectedScore = ((contrubutionScore / totalScore) * g_config.getFloat(ConfigManager::REWARD_BASE_RATE)); + int32_t lootRate = std::min(expectedScore, 1.0); - Player* player = g_game.getPlayerByGUID(playerId); + Player* player = g_game.getPlayerByGUID(playerId); - auto rewardContainer = Item::CreateItem(ITEM_REWARD_CONTAINER)->getContainer(); - rewardContainer->setIntAttr(ITEM_ATTRIBUTE_DATE, currentTime); - rewardContainer->setIntAttr(ITEM_ATTRIBUTE_REWARDID, getMonster()->getID()); + auto rewardContainer = Item::CreateItem(ITEM_REWARD_CONTAINER)->getContainer(); + rewardContainer->setIntAttr(ITEM_ATTRIBUTE_DATE, currentTime); + rewardContainer->setIntAttr(ITEM_ATTRIBUTE_REWARDID, getMonster()->getID()); - bool hasLoot = false; + bool hasLoot = false; - for (const auto& lootBlock : creatureLoot) { - float adjustedChance = (lootBlock.chance * lootRate) * g_config.getNumber(ConfigManager::RATE_LOOT); + for (const auto& lootBlock : creatureLoot) { + int32_t adjustedChance = (static_cast(lootBlock.chance) * lootRate) * g_config.getNumber(ConfigManager::RATE_LOOT); - if (lootBlock.unique && mostScoreContributor == playerId) { - // Ensure that the mostScoreContributor can receive multiple unique items + auto isTopPlayer = (playerId == topContributerId) ? true : false; + auto chance = uniform_random(1, MAX_LOOTCHANCE); auto count = uniform_random(1, lootBlock.countmax); - auto lootItem = Item::CreateItem(lootBlock.id, count); - lootItem->setIntAttr(ITEM_ATTRIBUTE_DATE, currentTime); - lootItem->setIntAttr(ITEM_ATTRIBUTE_REWARDID, getMonster()->getID()); - rewardContainer->internalAddThing(count, lootItem); - hasLoot = true; - } - else if (!lootBlock.unique) { - // Normal loot distribution for non-unique items - if (uniform_random(1, MAX_LOOTCHANCE) <= adjustedChance) { - auto count = uniform_random(1, lootBlock.countmax); + + if ((lootBlock.unique && isTopPlayer) || (chance <= adjustedChance )) { + // Ensure that the mostScoreContributor can receive multiple unique items auto lootItem = Item::CreateItem(lootBlock.id, count); lootItem->setIntAttr(ITEM_ATTRIBUTE_DATE, currentTime); - lootItem->setIntAttr(ITEM_ATTRIBUTE_REWARDID, getMonster()->getID()); - rewardContainer->internalAddThing(count, lootItem); - hasLoot = true; + lootItem->setIntAttr(ITEM_ATTRIBUTE_REWARDID, monsterId); + if (g_game.internalAddItem(rewardContainer, lootItem) == RETURNVALUE_NOERROR) { + hasLoot = true; + } else { + std::cout << "::Error in Boss Reward System:: Failed to add " + << lootItem->getName() + << " to player " + << player->getName() + << " for the kill of " + << getName() << std::endl; + } + } } - } - if (hasLoot) { - if (player) { - player->getRewardChest().internalAddThing(rewardContainer); - player->sendTextMessage(MESSAGE_LOOT, "The following items dropped by " + getMonster()->getName() + " are available in your reward chest: " + rewardContainer->getContentDescription() + "."); - } - else { - DBInsert rewardQuery("INSERT INTO `player_rewarditems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES "); - PropWriteStream propWriteStream; - - ItemBlockList itemList; - int32_t currentPid = 1; - for (Item* subItem : rewardContainer->getItemList()) { - itemList.emplace_back(currentPid, subItem); - } + if (hasLoot) { + if (player) { + g_game.internalAddItem(player->getRewardChest().getContainer(), rewardContainer); + player->sendTextMessage(MESSAGE_LOOT, "The following items dropped by " + getMonster()->getName() + " are available in your reward chest: " + rewardContainer->getContentDescription() + "."); + } else { + DBInsert rewardQuery("INSERT INTO `player_rewarditems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES "); + PropWriteStream propWriteStream; + + ItemBlockList itemList; + int32_t currentPid = 1; + for (Item* subItem : rewardContainer->getItemList()) { + itemList.emplace_back(currentPid, subItem); + } - IOLoginData::addRewardItems(playerId, itemList, rewardQuery, propWriteStream); + IOLoginData::addRewardItems(playerId, itemList, rewardQuery, propWriteStream); + } + } else if (player) { + player->sendTextMessage(MESSAGE_LOOT, "You did not receive any loot."); } - } - else if (player) { - player->sendTextMessage(MESSAGE_LOOT, "You did not receive any loot."); + g_game.resetDamageTracking(monsterId); } } - g_game.resetDamageTracking(monsterId); } setAttackedCreature(nullptr);