Feature Auto Loot [TFS 1.3]

Joined
Dec 1, 2017
Messages
75
Best answers
6
Likes
50
#1
I was bored so i did this code, thanks @Thexamx for the general help.



In player.h, above
Code:
std::unordered_set<uint32_t> attackedSet;
Add:
Code:
std::set<uint32_t> autoLootList;
Below:
Code:
bool hasLearnedInstantSpell(const std::string& spellName) const;
Add:
Code:
void addAutoLootItem(uint16_t itemId);
void removeAutoLootItem(uint16_t itemId);
bool getAutoLootItem(uint16_t itemId);
In player.cpp, add these lines:
Code:
void Player::addAutoLootItem(uint16_t itemId)
{
    autoLootList.insert(itemId);
}

void Player::removeAutoLootItem(uint16_t itemId)
{
    autoLootList.erase(itemId);
}

bool Player::getAutoLootItem(const uint16_t itemId)
{
    return autoLootList.find(itemId) != autoLootList.end();
}
In monsters.cpp, before:
Code:
if (!owner || owner->getStaminaMinutes() > 840) {
Add:
Code:
std::string autolooted = "";
Replace:
Code:
corpse->internalAddThing(item);
With:
Code:
                if (owner->getAutoLootItem(item->getID())) {
                    g_game.internalPlayerAddItem(owner, item, true, CONST_SLOT_WHEREEVER);
                    autolooted = autolooted + ", " + item->getNameDescription();
                } else if (g_game.internalAddItem(corpse, item) != RETURNVALUE_NOERROR) {
                   corpse->internalAddThing(item);
               }
Below:
Code:
std::ostringstream ss;
Add:
Code:
std::string lootMsg = corpse->getContentDescription();
And replace
Code:
ss << "Loot of " << nameDescription << ": " << corpse->getContentDescription();
With:
Code:
            if (autolooted != "" and corpse->getContentDescription() == "nothing") {
                lootMsg = autolooted.erase(0,2) + " that was auto looted";
            } else if (autolooted != "") {
                lootMsg =  corpse->getContentDescription() + " and " + autolooted.erase(0,2) + " was auto looted.";
            }
In luascript.cpp, add these lines:
Code:
//Autoloot wrote by Psychonaut#4421

int LuaScriptInterface::luaPlayerAddAutoLootItem(lua_State* L)
{
    // player:addAutoLootItem(itemId)
    Player* player = getUserdata<Player>(L, 1);
    if (!player) {
        lua_pushnil(L);
        return 1;
    }

    uint16_t itemId;
    if (isNumber(L, 2)) {
        itemId = getNumber<uint16_t>(L, 2);
    } else {
        itemId = Item::items.getItemIdByName(getString(L, 2));
        if (itemId == 0) {
            lua_pushnil(L);
            return 1;
        }
    }
    player->addAutoLootItem(itemId);
    pushBoolean(L, true);
    return 1;
}

int LuaScriptInterface::luaPlayerRemoveAutoLootItem(lua_State* L)
{
    // player:removeAutoLootItem(itemId)
    Player* player = getUserdata<Player>(L, 1);
    if (!player) {
        lua_pushnil(L);
        return 1;
    }

    uint16_t itemId;
    if (isNumber(L, 2)) {
        itemId = getNumber<uint16_t>(L, 2);
    } else {
        itemId = Item::items.getItemIdByName(getString(L, 2));
        if (itemId == 0) {
            lua_pushnil(L);
            return 1;
        }
    }
 
    player->removeAutoLootItem(itemId);
    pushBoolean(L, true);

    return 1;
}

int LuaScriptInterface::luaPlayerGetAutoLootItem(lua_State* L)
{
    // player:getAutoLootItem(itemId)
    Player* player = getUserdata<Player>(L, 1);
    if (!player) {
        lua_pushnil(L);
        return 1;
    }

    uint16_t itemId;
    if (isNumber(L, 2)) {
        itemId = getNumber<uint16_t>(L, 2);
    } else {
        itemId = Item::items.getItemIdByName(getString(L, 2));
        if (itemId == 0) {
            lua_pushnil(L);
            return 1;
        }
    }
 
    if (player->getAutoLootItem(itemId)) {
        pushBoolean(L, true);
    } else {
        pushBoolean(L, false);
    }

    return 1;
}

int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State* L)
{
    // player:getAutoLootList()
    Player* player = getUserdata<Player>(L, 1);

    if (player) {
        std::set<uint32_t> value = player->autoLootList;
    
        if (value.size() == 0) {
          lua_pushnil(L);
          return 1;
        }

        int index = 0;
        lua_createtable(L, value.size(), 0);
        for(auto i : value) {
            lua_pushnumber(L, i);
            lua_rawseti(L, -2, ++index);
        }
    
    } else {
        lua_pushnil(L);
    }

    return 1;
}
And in iologindata.cpp, below:
Code:
//load storage map
query.str(std::string());
query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID();
if ((result = db.storeQuery(query.str()))) {
    do {
        player->addStorageValue(result->getNumber<uint32_t>("key"), result->getNumber<int32_t>("value"), true);
    } while (result->next());
}
Add:

Code:
//load autoloot list set
query.str(std::string());
query << "SELECT `autoloot_list` FROM `player_autoloot` WHERE `player_id` = " << player->getGUID();
if ((result = db.storeQuery(query.str()))) {
    unsigned long lootlistSize;
    const char* autolootlist = result->getStream("autoloot_list", lootlistSize);
    PropStream propStreamList;
    propStreamList.init(autolootlist, lootlistSize);

    int16_t value;
    int16_t item = propStreamList.read<int16_t>(value);
    while (item) {
        player->addAutoLootItem(value);
        item = propStreamList.read<int16_t>(value);
    }
}
And above:
Code:
//save inbox items
Add:
Code:
//save autolootlist
query.str(std::string());
query << "DELETE FROM `player_autoloot` WHERE `player_id` = " << player->getGUID();
if (!db.executeQuery(query.str())) {
    return false;
}

PropWriteStream propWriteStreamAutoLoot;

for (auto i : player->autoLootList) {
    propWriteStreamAutoLoot.write<uint16_t>(i);
}

size_t lootlistSize;
const char* autolootlist = propWriteStreamAutoLoot.getStream(lootlistSize);

query.str(std::string());

DBInsert autolootQuery("INSERT INTO `player_autoloot` (`player_id`, `autoloot_list`) VALUES ");

    query << player->getGUID() << ',' << db.escapeBlob(autolootlist, lootlistSize);
    if (!autolootQuery.addRow(query)) {
        return false;
    }

if (!autolootQuery.execute()) {
    return false;
}
Note that in both you could use the same stream as conditions and clear it, but idk what you changed or not in the code.

Go to your database
and create a new table named player_autoloot with id(primary/auto increment), player_id(int) and autoloot_list(blob). Something like:

Code:
CREATE TABLE player_autoloot (
    id int NOT NULL AUTO_INCREMENT,
    player_id int NOT NULL,
    autoloot_list blob,
    PRIMARY KEY (id)
);
And then go to data/lib/compat/compat.lua(or where you wanna use it) and add these lines:
Lua:
--AutoLoot written by Psychonaut#4421
function getPlayerAutoLootItem(cid, itemId) local p = Player(cid) return p ~= nil and p:getAutoLootItem(itemId) or false end
function getPlayerAutoLootList(cid) local p = Player(cid) return p ~= nil and p:getAutoLootList() or false end
function removePlayerAutoLootItem(cid, itemId) local p = Player(cid) return p ~= nil and p:removeAutoLootItem(itemId) or false end
function addPlayerAutoLootItem(cid, itemId) local p = Player(cid) return p ~= nil and p:addAutoLootItem(itemId) or false end
These are the commands:

xml:
Code:
<talkaction words="!autoloot" script="autoloot.lua" />
<talkaction words="!add" separator=" " script="addautoloot.lua" />
<talkaction words="!remove" separator=" " script="remautoloot.lua" />
Lua:
function onSay(player, words, param)
    local list = "You're auto looting: "
    local alist = player:getAutoLootList()
 
    if alist then
        for _, item in ipairs(alist) do
            list = list .. (ItemType(item)):getName() .. ", "
        end
    else
        player:sendCancelMessage("The list is empty.")
        return false
    end
    player:sendTextMessage(MESSAGE_INFO_DESCR, list:sub(1, -3))
    return false
end
Lua:
function onSay(player, words, param)
    local itemType = ItemType(param)

    if itemType:getId() == 0 then
        itemType = ItemType(tonumber(param))
        if itemType:getName() == '' then
            player:sendCancelMessage("There is no item with that id or name.")
            return false
        end
    end
    if player:getAutoLootItem(itemType:getId()) then
        player:sendCancelMessage("You're already autolooting this item.")
        return false
    end

    player:addAutoLootItem(itemType:getId())
    player:sendTextMessage(MESSAGE_INFO_DESCR, "You're now auto looting " .. itemType:getName())
    return false
end
Lua:
function onSay(player, words, param)
    local itemType = ItemType(param)
 
    if itemType:getId() == 0 then
        itemType = ItemType(tonumber(param))
        if itemType:getName() == '' then
            player:sendCancelMessage("There is no item with that id or name.")
            return false
        end
    end

    if player:getAutoLootItem(itemType:getId()) then
        player:removeAutoLootItem(itemType:getId())
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You're not auto looting " .. itemType:getName() .. " anymore.")
    else
        player:sendCancelMessage("You're not autolooting this item.")
    end

    return false
end
The function can do a check for id/names but i'm doing in lua as i already need to getting the itemType anyway.
Sometimes when i copy part of a code here the identation goes away(and i can't fix it here), so tab it yourself where it happened.

You can call these functions in a npc if you doesn't wanna use talkactions or anywhere that you want.
 
Last edited by a moderator:
Joined
Dec 1, 2017
Messages
75
Best answers
6
Likes
50
#4
if players are in party who get priority?
The owner of the corpse, who did more dmg, party members can still open the corpse but the loot will be with who's the corpse owner(if he's auto looting), but the party members will get the msg too, like:
Loot of a rat: 3 gold coins that was auto looted
 
Joined
Dec 1, 2017
Messages
75
Best answers
6
Likes
50
#5
If you wanna do something like this when in party:


In monsters.cpp before:
Code:
 owner->getParty()->broadcastPartyLoot(ss.str());
Add:

Code:
ss << " by " << owner->getName();
But remove the dot before in "was auto looted", you can add it later if you want.
 

Nekiro

worst coder
Support Team
Joined
Sep 7, 2015
Messages
1,743
Best answers
74
Likes
509
#6
Looks good, nice release :)
Nice to see non profit contribution to the community.
 

Wirless

7.6 is the best :D
Joined
Nov 3, 2012
Messages
1,027
Best answers
1
Likes
187
Location
Ireland-Poland
#7
If you wanna do something like this when in party:


In monsters.cpp before:
Code:
 owner->getParty()->broadcastPartyLoot(ss.str());
Add:

Code:
ss << " by " << owner->getName();
But remove the dot before in "was auto looted", you can add it later if you want.
I am saying include it because of DEBUG you could get or Cloning of items!
 

Linxsis

Banned User
Joined
Nov 18, 2017
Messages
243
Best answers
10
Likes
80
#10
if 2 ppl enable sharing loot and both are loot owners because of party who gets the loot? with the first code you made.
If you believe this to be the case then provide the op with proof so that he/she may address the issue.
 

Nekiro

worst coder
Support Team
Joined
Sep 7, 2015
Messages
1,743
Best answers
74
Likes
509
#11
if 2 ppl enable sharing loot and both are loot owners because of party who gets the loot? with the first code you made.
If one player loots the item, 2nd cant, because it doesnt exist. Its created only once in monsters.cpp while creating loot. Also owner of corpse is only one and to this player item is transfered.
 

cesar10

Active Member
Joined
Aug 4, 2009
Messages
423
Best answers
0
Likes
33
#13
Cannot find the monster.cpp part
Code:
if (!owner || owner->getStaminaMinutes() > 840) {
Only code regarding "owner" is
Code:
Item* Monster::getCorpse(Creature* lastHitCreature, Creature* mostDamageCreature)
{
    Item* corpse = Creature::getCorpse(lastHitCreature, mostDamageCreature);
    if (corpse) {
        if (mostDamageCreature) {
            if (mostDamageCreature->getPlayer()) {
                corpse->setCorpseOwner(mostDamageCreature->getID());
            } else {
                const Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
                if (mostDamageCreatureMaster && mostDamageCreatureMaster->getPlayer()) {
                    corpse->setCorpseOwner(mostDamageCreatureMaster->getID());
                }
            }
        }
    }
    return corpse;
}
TFS 1.3 compiled today
 

cesar10

Active Member
Joined
Aug 4, 2009
Messages
423
Best answers
0
Likes
33
#14
Cant eddit sorry for spam was looking at monster.cpp not monsters.cpp
New to source edit sorry
 
Joined
Dec 24, 2010
Messages
104
Best answers
0
Likes
1
#17
@psychonaut


[ 1%] Building CXX object CMakeFiles/tfs.dir/src/luascript.cpp.o
/root/Otxserver-New/src/luascript.cpp:56:62: error: no ‘int LuaScriptInterface::luaPlayerAddAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerAddAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:80:65: error: no ‘int LuaScriptInterface::luaPlayerRemoveAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerRemoveAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:106:62: error: no ‘int LuaScriptInterface::luaPlayerGetAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerGetAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:135:62: error: no ‘int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State* L)
 
Joined
Jan 29, 2011
Messages
20
Best answers
0
Likes
0
#18
a have this problem too, you have solution ?

[ 1%] Building CXX object CMakeFiles/tfs.dir/src/luascript.cpp.o
/root/Otxserver-New/src/luascript.cpp:56:62: error: no ‘int LuaScriptInterface::luaPlayerAddAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerAddAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:80:65: error: no ‘int LuaScriptInterface::luaPlayerRemoveAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerRemoveAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:106:62: error: no ‘int LuaScriptInterface::luaPlayerGetAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerGetAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:135:62: error: no ‘int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State* L)
a have this problem too, you have solution ?
 
Last edited by a moderator:

flaviiojr

Active Member
Joined
Jan 20, 2017
Messages
230
Best answers
13
Likes
34
#19
@psychonaut
[ 1%] Building CXX object CMakeFiles/tfs.dir/src/luascript.cpp.o
/root/Otxserver-New/src/luascript.cpp:56:62: error: no ‘int LuaScriptInterface::luaPlayerAddAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerAddAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:80:65: error: no ‘int LuaScriptInterface::luaPlayerRemoveAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerRemoveAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:106:62: error: no ‘int LuaScriptInterface::luaPlayerGetAutoLootItem(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerGetAutoLootItem(lua_State* L)
^
/root/Otxserver-New/src/luascript.cpp:135:62: error: no ‘int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State*)’ member function declared in class ‘LuaScriptInterface’
int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State* L)
a have this problem too, you have solution ?
a have this problem too, you have solution ?
In luascript.cpp, above:
C++:
registerMethod("Player", "getIdleTime", LuaScriptInterface::luaPlayerGetIdleTime);
Add:
C++:
    registerMethod("Player", "AddAutoLootItem", LuaScriptInterface::luaPlayerAddAutoLootItem);
    registerMethod("Player", "RemoveAutoLootItem", LuaScriptInterface::luaPlayerRemoveAutoLootItem);
    registerMethod("Player", "GetAutoLootItem", LuaScriptInterface::luaPlayerGetAutoLootItem);
    registerMethod("Player", "GetAutoLootList", LuaScriptInterface::luaPlayerGetAutoLootList);
 
Joined
Dec 24, 2010
Messages
104
Best answers
0
Likes
1
#20
I will test a doubt the loot will go to the backpack that owns the item or will always go to the main backpack
 
Top