Skip to content

Commit

Permalink
[Feature/Enhancement/Custom] - Auto Loot, Quick Looting in stack and …
Browse files Browse the repository at this point in the history
…Auto Bank function (#184)

Auto loot using your manage loot containers quick loot categories and items filter, can be enabled in config.lua!
Quick loot in stack, up to 30 corpses, enabled using client option.
Auto Bank function, the dropped coins from monsters will be automatically deposited to your bank account, can be enabled in config.lua.
  • Loading branch information
omeranha committed Mar 10, 2022
1 parent e3df583 commit 5cb9ff7
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 10 deletions.
4 changes: 4 additions & 0 deletions config.lua.dist
Expand Up @@ -65,6 +65,10 @@ allConsoleLog = false
-- the non-stackable items will be moved to the selected depot chest(I - XVIII).
stashMoving = false
depotChest = 4
autoLoot = false
-- autoBank = true, the dropped coins from monsters will be automatically
-- deposited to your bank account.
autoBank = false

-- Stamina in Trainers
staminaTrainer = false
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_definitions.hpp
Expand Up @@ -67,6 +67,8 @@ enum booleanConfig_t {
TOGLE_SAVE_INTERVAL_CLEAN_MAP,
STASH_MOVING,
TOGLE_IMBUEMENT_SHRINE_STORAGE,
AUTOLOOT,
AUTOBANK,

LAST_BOOLEAN_CONFIG
};
Expand Down
2 changes: 2 additions & 0 deletions src/config/configmanager.cpp
Expand Up @@ -178,6 +178,8 @@ bool ConfigManager::load()
boolean[WEATHER_THUNDER] = getGlobalBoolean(L, "thunderEffect", false);
boolean[ALL_CONSOLE_LOG] = getGlobalBoolean(L, "allConsoleLog", false);
boolean[TOGGLE_FREE_QUEST] = getGlobalBoolean(L, "toggleFreeQuest", true);
boolean[AUTOLOOT] = getGlobalBoolean(L, "autoLoot", false);
boolean[AUTOBANK] = getGlobalBoolean(L, "autoBank", false);
boolean[STAMINA_TRAINER] = getGlobalBoolean(L, "staminaTrainer", false);
boolean[STAMINA_PZ] = getGlobalBoolean(L, "staminaPz", false);
boolean[SORT_LOOT_BY_CHANCE] = getGlobalBoolean(L, "sortLootByChance", false);
Expand Down
28 changes: 28 additions & 0 deletions src/creatures/creature.cpp
Expand Up @@ -649,6 +649,7 @@ void Creature::onDeath()
Party* party = attackerPlayer->getParty();
if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
attacker = party->getLeader();
mostDamageCreature = attacker;
}
}

Expand Down Expand Up @@ -726,6 +727,33 @@ bool Creature::dropCorpse(Creature* lastHitCreature, Creature* mostDamageCreatur
g_game.internalAddItem(tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT);
dropLoot(corpse->getContainer(), lastHitCreature);
corpse->startDecaying();
bool corpses = corpse->isRewardCorpse() && (corpse->getID() == ITEM_MALE_CORPSE || corpse->getID() == ITEM_FEMALE_CORPSE);
if (mostDamageCreature && mostDamageCreature->getPlayer() && !corpses) {
Player* player = mostDamageCreature->getPlayer();
if (g_configManager().getBoolean(AUTOBANK)) {
int32_t money = 0;
if (!corpse->getContainer()) {
return true;
}

for (Item* item : corpse->getContainer()->getItems()) {
money += item->getWorth();
g_game.internalRemoveItem(item, money);
}

if (money > 0) {
player->setBankBalance(player->getBankBalance() + money);
std::ostringstream ss;
ss << "Added " << money << " gold coins to your bank account.";
player->sendTextMessage(MESSAGE_STATUS, ss.str());
}
}

if (g_configManager().getBoolean(AUTOLOOT)) {
int32_t pos = tile->getStackposOfItem(player, corpse);
g_dispatcher.addTask(createTask(std::bind(&Game::playerQuickLoot, &g_game, mostDamageCreature->getID(), this->getPosition(), corpse->getClientID(), pos - 1, nullptr, false, true)));
}
}
}

// Scripting event onDeath
Expand Down
2 changes: 1 addition & 1 deletion src/creatures/players/player.cpp
Expand Up @@ -5599,7 +5599,7 @@ void Player::stowItem(Item* item, uint32_t count, bool allItems) {
}
} else if (item->getContainer()) {
itemDict = item->getContainer()->getStowableItems();
for (Item* containerItem : item->getContainer()->getItems()) {
for (Item* containerItem : item->getContainer()->getItems(true)) {
uint32_t depotChest = g_configManager().getNumber(DEPOTCHEST);
bool validDepot = depotChest > 0 && depotChest < 19;
if (g_configManager().getBoolean(STASH_MOVING) && containerItem && !containerItem->isStackable() && validDepot) {
Expand Down
65 changes: 59 additions & 6 deletions src/game/game.cpp
Expand Up @@ -4455,7 +4455,7 @@ void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
g_events->eventPlayerOnLookInBattleList(player, creature, lookDistance);
}

void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spriteId, uint8_t stackPos, Item* defaultItem)
void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spriteId, uint8_t stackPos, Item* defaultItem, bool lootAllCorpses, bool autoLoot)
{
Player* player = getPlayerByID(playerId);
if (!player) {
Expand All @@ -4467,12 +4467,12 @@ void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spri
SchedulerTask* task = createSchedulerTask(delay, std::bind(
&Game::playerQuickLoot,
this, player->getID(), pos,
spriteId, stackPos, defaultItem));
spriteId, stackPos, defaultItem, lootAllCorpses, autoLoot));
player->setNextActionTask(task);
return;
}

if (pos.x != 0xffff) {
if (!autoLoot && pos.x != 0xffff) {
if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) {
//need to walk to the corpse first before looting it
std::forward_list<Direction> listDir;
Expand All @@ -4481,7 +4481,7 @@ void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spri
SchedulerTask* task = createSchedulerTask(0, std::bind(
&Game::playerQuickLoot,
this, player->getID(), pos,
spriteId, stackPos, defaultItem));
spriteId, stackPos, defaultItem, lootAllCorpses, autoLoot));
player->setNextWalkActionTask(task);
} else {
player->sendCancelMessage(RETURNVALUE_THEREISNOWAY);
Expand Down Expand Up @@ -4517,6 +4517,10 @@ void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spri
Container* corpse = nullptr;
if (pos.x == 0xffff) {
corpse = item->getParent()->getContainer();
if (corpse && corpse->getID() == ITEM_BROWSEFIELD) {
corpse = item->getContainer();
browseField = true;
}
} else {
corpse = item->getContainer();
}
Expand All @@ -4534,7 +4538,7 @@ void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spri
}
}

if (pos.x == 0xffff) {
if (pos.x == 0xffff && !browseField) {
uint32_t worth = item->getWorth();
ObjectCategory_t category = getObjectCategory(item);
ReturnValue ret = internalQuickLootItem(player, item, category);
Expand Down Expand Up @@ -4573,13 +4577,62 @@ void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spri
if (corpse->isRewardCorpse()) {
g_actions->useItem(player, pos, 0, corpse, false);
} else {
internalQuickLootCorpse(player, corpse);
if (!lootAllCorpses) {
internalQuickLootCorpse(player, corpse);
} else {
playerLootAllCorpses(player, pos, lootAllCorpses);
}
}
}

return;
}

void Game::playerLootAllCorpses(Player* player, const Position& pos, bool lootAllCorpses) {
if (lootAllCorpses) {
Tile *tile = g_game.map.getTile(pos.x, pos.y, pos.z);
if (!tile) {
player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
return;
}

const TileItemVector *itemVector = tile->getItemList();
uint16_t corpses = 0;
for (Item *tileItem: *itemVector) {
if (!tileItem) {
continue;
}

Container *tileCorpse = tileItem->getContainer();
if (!tileCorpse || !tileCorpse->isCorpse() || tileCorpse->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID) || tileCorpse->hasAttribute(ITEM_ATTRIBUTE_ACTIONID)) {
continue;
}

if (!tileCorpse->isRewardCorpse() && !player->canOpenCorpse(tileCorpse->getCorpseOwner())) {
continue;
}

corpses++;
internalQuickLootCorpse(player, tileCorpse);
if (corpses >= 30) {
break;
}
}

if (corpses > 0) {
if (corpses > 1) {
std::stringstream string;
string << "You looted " << corpses << " corpses.";
player->sendTextMessage(MESSAGE_LOOT, string.str());
}

return;
}
}

browseField = false;
}

void Game::playerSetLootContainer(uint32_t playerId, ObjectCategory_t category, const Position& pos, uint16_t spriteId, uint8_t stackPos)
{
Player* player = getPlayerByID(playerId);
Expand Down
6 changes: 4 additions & 2 deletions src/game/game.h
Expand Up @@ -315,8 +315,9 @@ class Game
void playerSetFightModes(uint32_t playerId, FightMode_t fightMode, bool chaseMode, bool secureMode);
void playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos);
void playerLookInBattleList(uint32_t playerId, uint32_t creatureId);
void playerQuickLoot(uint32_t playerId, const Position& pos,
uint16_t spriteId, uint8_t stackPos, Item* defaultItem = nullptr);
void playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spriteId, uint8_t stackPos,
Item* defaultItem = nullptr, bool lootAllCorpses = false, bool autoLoot = false);
void playerLootAllCorpses(Player* player, const Position& pos, bool lootAllCorpses);
void playerSetLootContainer(uint32_t playerId, ObjectCategory_t category,
const Position& pos, uint16_t spriteId, uint8_t stackPos);
void playerClearLootContainer(uint32_t playerId, ObjectCategory_t category);;
Expand Down Expand Up @@ -608,6 +609,7 @@ class Game
static constexpr int32_t SUNRISE = 360;

bool isDay = false;
bool browseField = false;

GameState_t gameState = GAME_STATE_NORMAL;
WorldType_t worldType = WORLD_TYPE_PVP;
Expand Down
4 changes: 3 additions & 1 deletion src/server/network/protocol/protocolgame.cpp
Expand Up @@ -1269,7 +1269,9 @@ void ProtocolGame::parseQuickLoot(NetworkMessage &msg)
Position pos = msg.getPosition();
uint16_t spriteId = msg.get<uint16_t>();
uint8_t stackpos = msg.getByte();
addGameTask(&Game::playerQuickLoot, player->getID(), pos, spriteId, stackpos, nullptr);
bool lootAllCorpses = msg.getByte();
bool autoLoot = msg.getByte();
addGameTask(&Game::playerQuickLoot, player->getID(), pos, spriteId, stackpos, nullptr, lootAllCorpses, autoLoot);
}

void ProtocolGame::parseLootContainer(NetworkMessage &msg)
Expand Down

0 comments on commit 5cb9ff7

Please sign in to comment.