Skip to content

Commit

Permalink
Adjustments to Monster::death for Reward System
Browse files Browse the repository at this point in the history
-Switched to using game::internalAddItem
-Reduced code duplication
-Improved Readability
-Added error reporting to output stream for failure to add items.
Codinablack committed Dec 1, 2024
1 parent 8bb2536 commit 4dd2f1b
Showing 1 changed file with 73 additions and 94 deletions.
167 changes: 73 additions & 94 deletions src/monster.cpp
Original file line number Diff line number Diff line change
@@ -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<int32_t>(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<int32_t>(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);

0 comments on commit 4dd2f1b

Please sign in to comment.