Feature Auto Loot Sytem for TFS 1.3

login12

void newbie scripter()
Joined
Feb 26, 2011
Messages
153
Best answers
0
Reaction score
18
Location
Brazil
Some words...
Yo. I developed this system as a method of study. (C++). If u found some bug, report it here and I will fix that.
thanks for @Delusion for the help. This system have was inspired in Auto Loot System by @psychonaut.
This system was created in the latest version of tfs.

Auto Loot System for TFS 1.3
autoloot.png
How it works?
Simple, when you kill some monster and open the corpse (you need click in corpse to loot), the items go for you character.
autoloot.gif

Installation
in actions.cpp, find:
C++:
if (corpseOwner != 0 && !player->canOpenCorpse(corpseOwner)) {
    return RETURNVALUE_YOUARENOTTHEOWNER;
}
and change it for:
C++:
if (corpseOwner != 0 && !player->canOpenCorpse(corpseOwner)) {
    return RETURNVALUE_YOUARENOTTHEOWNER;
} else {
    if (player->canOpenCorpse(corpseOwner) && player->autoLootList.size() != 0) {
        if (player->getCapacity() > 100 * 100) { //Minimum of Capacity for autoloot works. (100 CAP)
            for (Item* item : container->getItemList()) {
                if (player->getItemFromAutoLoot(item->getID())) {
                    std::ostringstream msgAutoLoot;
                    msgAutoLoot << "You looted a " << item->getItemCount() << "x " << item->getName() << ".";
                    g_game.internalMoveItem(container, player, CONST_SLOT_WHEREEVER, item, item->getItemCount(), nullptr);
                    player->sendTextMessage(MESSAGE_INFO_DESCR, msgAutoLoot.str());
                }
            }
        } else {
            player->sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, you don't have enough capacity to use auto loot, so it has been disabled. (100+ capacity is required)");
        }
    }
}
in player.h, below
C++:
std::unordered_set<uint32_t> VIPList;
Add this
C++:
std::set<uint32_t> autoLootList;
below that:
C++:
bool hasLearnedInstantSpell(const std::string& spellName) const;
Add this
C++:
void addItemToAutoLoot(uint16_t itemId);
void removeItemFromAutoLoot(uint16_t itemId);
bool getItemFromAutoLoot(uint16_t itemId);
in player.cpp, in the end... add

C++:
void Player::addItemToAutoLoot(uint16_t itemId)
{
    autoLootList.insert(itemId);
}

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

bool Player::getItemFromAutoLoot(const uint16_t itemId)
{
    return autoLootList.find(itemId) != autoLootList.end();
}
in luascript.cpp, find
C++:
registerMethod("Player", "getFightMode", LuaScriptInterface::luaPlayerGetFightMode);
add that below
C++:
    registerMethod("Player", "addItemToAutoLoot", LuaScriptInterface::luaPlayerAddItemToAutoLoot);
    registerMethod("Player", "removeItemFromAutoLoot", LuaScriptInterface::luaPlayerRemoveItemFromAutoLoot);
    registerMethod("Player", "getItemFromAutoLoot", LuaScriptInterface::luaPlayerGetItemFromAutoLoot);
    registerMethod("Player", "getAutoLootList", LuaScriptInterface::luaPlayerGetAutoLootList);
yet in luascript.cpp, find this function
C++:
int LuaScriptInterface::luaPlayerGetFightMode(lua_State* L)
{
    // player:getFightMode()
    Player* player = getUserdata<Player>(L, 1);
    if (player) {
        lua_pushnumber(L, player->fightMode);
    } else {
        lua_pushnil(L);
    }
    return 1;
}
below this whole function, add
C++:
int LuaScriptInterface::luaPlayerAddItemToAutoLoot(lua_State* L)
{
    // player:addItemToAutoLoot(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->addItemToAutoLoot(itemId);
    pushBoolean(L, true);
    return 1;
}

int LuaScriptInterface::luaPlayerRemoveItemFromAutoLoot(lua_State* L)
{
    // player:removeItemFromAutoLoot(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->removeItemFromAutoLoot(itemId);
    pushBoolean(L, true);

    return 1;
}

int LuaScriptInterface::luaPlayerGetItemFromAutoLoot(lua_State* L)
{
    // player:getItemFromAutoLoot(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->getItemFromAutoLoot(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;
}
in luascript.h, find
C++:
static int luaPlayerGetFightMode(lua_State* L);
add below
C++:
static int luaPlayerAddItemToAutoLoot(lua_State* L);
static int luaPlayerRemoveItemFromAutoLoot(lua_State* L);
static int luaPlayerGetItemFromAutoLoot(lua_State* L);
static int luaPlayerGetAutoLootList(lua_State* L);
And in iologindata.cpp, below:
C++:
    //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
C++:
    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->addItemToAutoLoot(value);
            item = propStreamList.read<int16_t>(value);
        }
    }
And above:
C++:
//save inbox items
add
C++:
    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;
    }
now, go to your database and execute this query:
Code:
CREATE TABLE player_autoloot (
    id int NOT NULL AUTO_INCREMENT,
    player_id int NOT NULL,
    autoloot_list blob,
    PRIMARY KEY (id)
);
go your data/scripts/talkactions and create this file:

autoloot.lua
Lua:
local talk = TalkAction("!autoloot")

function talk.onSay(player, words, param)
    local i = player:getAutoLootList()
    local cache = "Check your loot list: "
    local split = param:split(",")
    local action = split[1]

    if param == "list" then
        if i then
            for _, item in ipairs(i) do
                cache = cache .. (ItemType(item)):getName() .. ", "
            end
        else
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Your list is empty! Add some item and try again.")
            return false
        end

        player:sendTextMessage(MESSAGE_INFO_DESCR, cache:sub(1, -3))
        return false
    end

   if action == "add" then
        local item = split[2]:gsub("%s+", "", 1)
        local itemType = ItemType(item)
        if itemType:getId() == 0 then
            itemType = ItemType(tonumber(item))
            if itemType:getName() == '' then
                player:sendCancelMessage("There is no item with that id or name.")
                return false
            end
        end

        if player:getItemFromAutoLoot(itemType:getId()) then
            player:sendCancelMessage("You're already autolooting this item.")
            return false
        end

        player:addItemToAutoLoot(itemType:getId())
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You're now auto looting " .. itemType:getName())
        return false
    elseif action == "remove" then
        local item = split[2]:gsub("%s+", "", 1)
        local itemType = ItemType(item)
        if itemType:getId() == 0 then
            itemType = ItemType(tonumber(item))
            if itemType:getName() == '' then
                player:sendCancelMessage("There is no item with that id or name.")
                return false
            end
        end

        if player:getItemFromAutoLoot(itemType:getId()) then
            player:removeItemFromAutoLoot(itemType:getId())
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You removed the " .. itemType:getName() .. " from your loot list.")
        else
            player:sendCancelMessage("This item does not exist in your loot list.")
        end
        return false           
    end


    player:sendTextMessage(MESSAGE_EVENT_ORANGE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items")
    return false
end

talk:separator(" ")
talk:register()
That's it, I hope you have fun.
If you found some bug, let me know.

Things I want do:

Transform the LUA files into one.
Optimize the loot message.
Add ModalWindow


Cheers~
 

Attachments

Last edited:

oen432

Veteran OT User
Joined
Oct 3, 2014
Messages
465
Best answers
9
Reaction score
428
Location
Poland
Hold on, since when there is TFS 1.4?
 

Delusion

Divine Intellect
Support Team
Joined
Feb 14, 2015
Messages
5,233
Best answers
511
Reaction score
2,860
Hold on, since when there is TFS 1.4?
TFS 1.4 will be used as the release version of 1.3, since 1.3 has basically been a "bleeding edge" branch for years. By doing so, it's easier to identify if someone is using the release version or they're somewhere along the bleeding edge branch, which could be missing code.

This thread should not be marked as 1.4 because of that reason, we're not on release version yet.
 
OP
login12

login12

void newbie scripter()
Joined
Feb 26, 2011
Messages
153
Best answers
0
Reaction score
18
Location
Brazil
Ok, if you or some mod can edit the title of this topic, please make it.
I back yesterday for this world and make a mistake with informations in docs. (my head is so heavy).

@Topic ~

Yo! I updated the code right now.

Change Log
  • All lua scripts now are merged into one, resulting in a single command to administer the autoloot system.
    autoloot.png

  • I also added some checks in the script so that it doesn't run if the character has no items added to the autoloot list. (optimization). Capacity check is also here now, if the character has no more than 100 cap, a message is returned to the player stating that it was not possible to loot. (In the future I may make this configurable through config.lua).
    cap.png
for now is that, i hope u like.
cheers
 
Last edited:

Awesomedudei

Revolutionot.com
Joined
Jan 20, 2010
Messages
313
Best answers
0
Reaction score
61
Location
Sweden
Amazing work @login12 !

I'll be swapping out my current autoloot system for this. Appreciate your work!
 

Ernstjan

Member
Joined
May 17, 2008
Messages
744
Best answers
0
Reaction score
24
Location
Vriezenveen,The Netherlands
I followed this step by step.. it didnt work nor do anything no errors in console...
So figured i maybe had to add the talkaction in the talkactions.xml
wich I did, using this line:
Code:
<talkaction words="!autoloot" script="autoloot.lua" />
Then i tried to cast the command ingame and my client debugged instantly after casting...

Edit: I added this talkaction again but now it doesnt debug me anymore, it does nothing at all.
 

Awesomedudei

Revolutionot.com
Joined
Jan 20, 2010
Messages
313
Best answers
0
Reaction score
61
Location
Sweden
I followed this step by step.. it didnt work nor do anything no errors in console...
So figured i maybe had to add the talkaction in the talkactions.xml
wich I did, using this line:
Code:
<talkaction words="!autoloot" script="autoloot.lua" />
Then i tried to cast the command ingame and my client debugged instantly after casting...

Edit: I added this talkaction again but now it doesnt debug me anymore, it does nothing at all.
You must have done something wrong as I just installed this without issue :p

Redo it step by step.

Are you using TFS 1.3?
 

Ernstjan

Member
Joined
May 17, 2008
Messages
744
Best answers
0
Reaction score
24
Location
Vriezenveen,The Netherlands
Ehh, but I did everything step by step.. If i redo I'd do the same... Maybe someone can add me in discord and check it for me? Henkiie#5951
 
OP
login12

login12

void newbie scripter()
Joined
Feb 26, 2011
Messages
153
Best answers
0
Reaction score
18
Location
Brazil
Ehh, but I did everything step by step.. If i redo I'd do the same... Maybe someone can add me in discord and check it for me? Henkiie#5951
What version of TFS u are using? Maybe it don't support a revscriptsys yet.
So try it:

1. remove you talkaction.lua of this script in (data/scripts/talkactions)
2. go to data/talkactions/scripts and put this script:

Lua:
function onSay(player, words, param)
    local i = player:getAutoLootList()
    local cache = "Check your loot list: "
    local split = param:split(",")
    local action = split[1]

    if param == "list" then
        if i then
            for _, item in ipairs(i) do
                cache = cache .. (ItemType(item)):getName() .. ", "
            end
        else
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Your list is empty! Add some item and try again.")
            return false
        end

        player:sendTextMessage(MESSAGE_INFO_DESCR, cache:sub(1, -3))
        return false
    end

   if action == "add" then
        local item = split[2]:gsub("%s+", "", 1)
        local itemType = ItemType(item)
        if itemType:getId() == 0 then
            itemType = ItemType(tonumber(item))
            if itemType:getName() == '' then
                player:sendCancelMessage("There is no item with that id or name.")
                return false
            end
        end

        if player:getItemFromAutoLoot(itemType:getId()) then
            player:sendCancelMessage("You're already autolooting this item.")
            return false
        end

        player:addItemToAutoLoot(itemType:getId())
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You're now auto looting " .. itemType:getName())
        return false
    elseif action == "remove" then
        local item = split[2]:gsub("%s+", "", 1)
        local itemType = ItemType(item)
        if itemType:getId() == 0 then
            itemType = ItemType(tonumber(item))
            if itemType:getName() == '' then
                player:sendCancelMessage("There is no item with that id or name.")
                return false
            end
        end

        if player:getItemFromAutoLoot(itemType:getId()) then
            player:removeItemFromAutoLoot(itemType:getId())
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You removed the " .. itemType:getName() .. " from your loot list.")
        else
            player:sendCancelMessage("This item does not exist in your loot list.")
        end
        return false           
    end


    player:sendTextMessage(MESSAGE_EVENT_ORANGE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items")
    return false
end
3. register it on xml like:
XML:
<talkaction words="!autoloot" separator=" " script="autoloot.lua" />
Tell me if it work for u.
 

Ernstjan

Member
Joined
May 17, 2008
Messages
744
Best answers
0
Reaction score
24
Location
Vriezenveen,The Netherlands
What version of TFS u are using? Maybe it don't support a revscriptsys yet.
So try it:

1. remove you talkaction.lua of this script in (data/scripts/talkactions)
2. go to data/talkactions/scripts and put this script:

Lua:
function onSay(player, words, param)
    local i = player:getAutoLootList()
    local cache = "Check your loot list: "
    local split = param:split(",")
    local action = split[1]

    if param == "list" then
        if i then
            for _, item in ipairs(i) do
                cache = cache .. (ItemType(item)):getName() .. ", "
            end
        else
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Your list is empty! Add some item and try again.")
            return false
        end

        player:sendTextMessage(MESSAGE_INFO_DESCR, cache:sub(1, -3))
        return false
    end

   if action == "add" then
        local item = split[2]:gsub("%s+", "", 1)
        local itemType = ItemType(item)
        if itemType:getId() == 0 then
            itemType = ItemType(tonumber(item))
            if itemType:getName() == '' then
                player:sendCancelMessage("There is no item with that id or name.")
                return false
            end
        end

        if player:getItemFromAutoLoot(itemType:getId()) then
            player:sendCancelMessage("You're already autolooting this item.")
            return false
        end

        player:addItemToAutoLoot(itemType:getId())
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You're now auto looting " .. itemType:getName())
        return false
    elseif action == "remove" then
        local item = split[2]:gsub("%s+", "", 1)
        local itemType = ItemType(item)
        if itemType:getId() == 0 then
            itemType = ItemType(tonumber(item))
            if itemType:getName() == '' then
                player:sendCancelMessage("There is no item with that id or name.")
                return false
            end
        end

        if player:getItemFromAutoLoot(itemType:getId()) then
            player:removeItemFromAutoLoot(itemType:getId())
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You removed the " .. itemType:getName() .. " from your loot list.")
        else
            player:sendCancelMessage("This item does not exist in your loot list.")
        end
        return false        
    end


    player:sendTextMessage(MESSAGE_EVENT_ORANGE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items")
    return false
end
3. register it on xml like:
XML:
<talkaction words="!autoloot" separator=" " script="autoloot.lua" />
Tell me if it work for u.
I did that what you said now when I cast the command on my GM char it debugs, when I relog to player it does nothing just shows !autoloot.

I'm using TFS 1.3, If im not misstaking...

Maybe you can add me on discord and check it with me? Henkiie#5951
 
OP
login12

login12

void newbie scripter()
Joined
Feb 26, 2011
Messages
153
Best answers
0
Reaction score
18
Location
Brazil
I did that what you said now when I cast the command on my GM char it debugs, when I relog to player it does nothing just shows !autoloot.

I'm using TFS 1.3, If im not misstaking...

Maybe you can add me on discord and check it with me? Henkiie#5951
u need have certain of what version u are using.
Idk why u got debug if u using tfs 1.x and make everything like a post...
 

Ernstjan

Member
Joined
May 17, 2008
Messages
744
Best answers
0
Reaction score
24
Location
Vriezenveen,The Netherlands
u need have certain of what version u are using.
Idk why u got debug if u using tfs 1.x and make everything like a post...
Support RepresentativeFriday, October 18, 2019 12:54 AM
There is no TFS 1.3 really, what you have installed is just master branch, which should be backwards compatible with TFS 1.2.
Thats what i was told by the person providing me the host and server. I read somewhere it was 1.3... but I'm not sure
 

celohere

Active Member
Joined
Nov 27, 2007
Messages
107
Best answers
4
Reaction score
41
I did that what you said now when I cast the command on my GM char it debugs, when I relog to player it does nothing just shows !autoloot.

I'm using TFS 1.3, If im not misstaking...

Maybe you can add me on discord and check it with me? Henkiie#5951
try to change this part on the talkaction :
Lua:
player:sendTextMessage(MESSAGE_EVENT_ORANGE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items")
for :
Lua:
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items")
 

Ernstjan

Member
Joined
May 17, 2008
Messages
744
Best answers
0
Reaction score
24
Location
Vriezenveen,The Netherlands
try to change this part on the talkaction :
Lua:
player:sendTextMessage(MESSAGE_EVENT_ORANGE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items")
for :
Lua:
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items")
Still debugged me :p thx for the efford tho

Only debugs on my GM char, on normal player chars it just doesnt do anything when you cast the command
 
OP
login12

login12

void newbie scripter()
Joined
Feb 26, 2011
Messages
153
Best answers
0
Reaction score
18
Location
Brazil
Its probaly happens because u are using one tfs without some function used here (or with custom changes).
So, i can't help u with that, u need check for u self.

It should work in tfs 1.2 and 1.3 without problems.
 

celohere

Active Member
Joined
Nov 27, 2007
Messages
107
Best answers
4
Reaction score
41
hey @login12 its not working with items that come inside bags on monsters ,can you fix it?and thanks for this great system =)
 
Top