• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Feature Auto Loot [TFS 1.3]

^Edit up post: I wanted to mention Togu, not Tagu. @Togu
a1vMOP8.png
 
Ok, the way to adjust the function is to add this lines in the luascript.h:

C++:
static int luaPlayerAddAutoLootItem(lua_State* L);
        static int luaPlayerRemoveAutoLootItem(lua_State* L);
        static int luaPlayerGetAutoLootItem(lua_State* L);
        static int luaPlayerGetAutoLootList(lua_State* L);

And after that, you have to change this piece of code in monsters.cpp:

C++:
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.";
            }

To this one:

Code:
if (autolooted != "" && 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.";
            }

Well, with this changes mine compiled ok!

Now, I have a problem too.

As I tried to use the talk action commands, an error is reported:

Code:
Lua Script Error: [TalkAction Interface]
data/talkactions/scripts/autoloot.lua:onSay
data/talkactions/scripts/autoloot.lua:23: attempt to call method 'getAutoLootList' (a nil value)
stack traceback:
        [C]: in function 'getAutoLootList'
        data/talkactions/scripts/autoloot.lua:23: in function <data/talkactions/scripts/autoloot.lua:21>

I understand that the method "getAutoLootList" is returning a nil value, so I think that the functions add to compat.lua aren't being loaded.
I already registered the talk action and their scripts.

Anyone can help here?
 
C++:
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.";
            }

To this one:

C++:
if (autolooted != "" && 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.";
            }
What's the difference here?

Code:
Lua Script Error: [TalkAction Interface]
data/talkactions/scripts/autoloot.lua:onSay
data/talkactions/scripts/autoloot.lua:23: attempt to call method 'getAutoLootList' (a nil value)
stack traceback:
        [C]: in function 'getAutoLootList'
        data/talkactions/scripts/autoloot.lua:23: in function <data/talkactions/scripts/autoloot.lua:21>

I understand that the method "getAutoLootList" is returning a nil value, so I think that the functions add to compat.lua aren't being loaded.
I already registered the talk action and their scripts.

Anyone can help here?
That error means the program cannot find a function called getAutoLootList, you did something wrong with this one.
 
no, he needs to registerMethod the functions in the main post because psychonaut left them out
in luascript.cpp where the rest of the player registermethods are, add these:
C++:
registerMethod("Player", "addAutoLootItem", LuaScriptInterface::luaPlayerAddAutoLootItem);
registerMethod("Player", "removeAutoLootItem", LuaScriptInterface::luaPlayerRemoveAutoLootItem);
registerMethod("Player", "getAutoLootItem", LuaScriptInterface::luaPlayerGetAutoLootItem);
registerMethod("Player", "getAutoLootList", LuaScriptInterface::luaPlayerGetAutoLootList);
 
What's the difference here?
That error means the program cannot find a function called getAutoLootList, you did something wrong with this one.
The difference is the "&&" instead of the "and". I'm not that good in C++, but I think that the Boolean operator that represents "AND" is "&&", as the "OR" is "||".

no, he needs to registerMethod the functions in the main post because psychonaut left them out
in luascript.cpp where the rest of the player registermethods are, add these:
C++:
registerMethod("Player", "addAutoLootItem", LuaScriptInterface::luaPlayerAddAutoLootItem);
registerMethod("Player", "removeAutoLootItem", LuaScriptInterface::luaPlayerRemoveAutoLootItem);
registerMethod("Player", "getAutoLootItem", LuaScriptInterface::luaPlayerGetAutoLootItem);
registerMethod("Player", "getAutoLootList", LuaScriptInterface::luaPlayerGetAutoLootList);
Thanks, @Vulcan_ . It worked! :)
 
The difference is the "&&" instead of the "and". I'm not that good in C++, but I think that the Boolean operator that represents "AND" is "&&", as the "OR" is "||".


Thanks, @Vulcan_ . It worked! :)
I'm sorry, you are right. I was not able to see the difference by reading it lol.
 
jgjfys.png

Fix for this?
in player.h used codes
C++:
std::unordered_set<uint32_t> autoLootList;
> No error
player.h
C++:
std::set<uint32_t> autoLootList;
> compiler error
player.h
C++:
std::forward_list<uint32_t> autoLootList;
> compiler error
 
jgjfys.png

Fix for this?
in player.h used codes
C++:
std::unordered_set<uint32_t> autoLootList;
> No error
player.h
C++:
std::set<uint32_t> autoLootList;
> compiler error
player.h
C++:
std::forward_list<uint32_t> autoLootList;
> compiler error

same error here.
 
jgjfys.png

Fix for this?
in player.h used codes
C++:
std::unordered_set<uint32_t> autoLootList;
> No error
player.h
C++:
std::set<uint32_t> autoLootList;
> compiler error
player.h
C++:
std::forward_list<uint32_t> autoLootList;
> compiler error
Post your monsters.cpp
 
This is a mess, I won't point to anyone, but remember that developers who wrote this did it as a hobby and FOR FREE, okay, the code from @psychonaut have some errors, but they might be because he did this because he was bored, and coding is fun except when you have to deal with cry babies complaining about some very simple lines not working. Really guys, if you come to the C++ codes section, try to read and understand code, creating a server is not just to copy and paste other people's systems.

Now, I'm going to TRY to explain every error I think the system have.

first, psychonaut didn't post the code to register the lua functions, and you need to do that so your lua code will recognize the addloot functions.

As @flaviiojr said, on luascript.cpp search for:

Lua:
registerMethod("Player", "getFightMode", LuaScriptInterface::luaPlayerGetFightMode);

That should be your last player method if you are using a recent TFS 1.3, below that add:

Code:
registerMethod("Player", "addAutoLootItem", LuaScriptInterface::luaPlayerAddAutoLootItem);
registerMethod("Player", "removeAutoLootItem", LuaScriptInterface::luaPlayerRemoveAutoLootItem);
registerMethod("Player", "getAutoLootItem", LuaScriptInterface::luaPlayerGetAutoLootItem);
registerMethod("Player", "getAutoLootList", LuaScriptInterface::luaPlayerGetAutoLootList);

Now, go to luascript.h and search for:

Code:
static int luaPlayerGetFightMode(lua_State* L);

And add below that:

Code:
static int luaPlayerAddAutoLootItem(lua_State* L);
static int luaPlayerRemoveAutoLootItem(lua_State* L);
static int luaPlayerGetAutoLootItem(lua_State* L);
static int luaPlayerGetAutoLootList(lua_State* L);

Now, the next error is the one of people claiming that there is no loot message anymore, first there is a typo mistake on this part of code that the OP told everyone to add

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.";            }

If you read carefully, it says "if (autolooted != "" and corpse->....." the AND on C++ is &&, so you have to change that, it will look like this:

Code:
  if (autolooted != "" && 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.";            }

Now, the next mistake is, that you were told to REPLACE the line with "ss << "Loot of " << nameDescription..." so after that last if block you need to add it again but with the lootMsg variable, so one line below add:

Code:
ss << "Loot of " << nameDescription << ": " << lootMsg;

Now the last mistake is that after all those, the system at all doesn't works (it doesn't take the item), that because you where told to REPLACE the line with "corpse->internalAddThing(item);" to the following:

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);
               }

Which is wrong, what you really have to reaplce is the entire if block, so.

REPLACE:

Code:
if (g_game.internalAddItem(corpse, item) != RETURNVALUE_NOERROR) {
                    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);
               }

So your function create loot over monsters.cpp should look like this:

Code:
void MonsterType::createLoot(Container* corpse)
{
    if (g_config.getNumber(ConfigManager::RATE_LOOT) == 0) {
        corpse->startDecaying();
        return;
    }

    Player* owner = g_game.getPlayerByID(corpse->getCorpseOwner());
    std::string autolooted = "";
    if (!owner || owner->getStaminaMinutes() > 840) {
        for (auto it = info.lootItems.rbegin(), end = info.lootItems.rend(); it != end; ++it) {
            auto itemList = createLootItem(*it);
            if (itemList.empty()) {
                continue;
            }

            for (Item* item : itemList) {
                //check containers
                if (Container* container = item->getContainer()) {
                    if (!createLootContainer(container, *it)) {
                        delete container;
                        continue;
                    }
                }

                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);
                }
            }
        }

        if (owner) {
            std::ostringstream ss;
            std::string lootMsg = corpse->getContentDescription();
            //ss << "Loot of " << nameDescription << ": " << corpse->getContentDescription(); -- change for autoloot system
            if (autolooted != "" && corpse->getContentDescription() == "nothing"){
                lootMsg = autolooted.erase(0,2) + " that was autolooted";
            } else if (autolooted != ""){
                lootMsg = corpse->getContentDescription() + " and " + autolooted.erase(0,2) + " was auto looted";
            }

            ss << "Loot of " << nameDescription << ": " << lootMsg;

            if (owner->getParty()) {
                ss << " by " << owner->getName();
                owner->getParty()->broadcastPartyLoot(ss.str());
            } else {
                owner->sendTextMessage(MESSAGE_LOOT, ss.str());
            }
        }
    } else {
        std::ostringstream ss;
        ss << "Loot of " << nameDescription << ": nothing (due to low stamina)";

        if (owner->getParty()) {
            owner->getParty()->broadcastPartyLoot(ss.str());
        } else {
            owner->sendTextMessage(MESSAGE_LOOT, ss.str());
        }
    }

    corpse->startDecaying();
}

Be sure to read my post slowly and step by step to understand what you have to do, and remember, we are helping with hope to receive no more than a thanks in exchange, nobody is perfect, and nobody will like to help a crybaby just because they don't understand the code, maybe I'm missing something too, I read the whole thread and I was able to figure out how to make it works (I'm a developer, but I'm not a C++ developer).

Best regards
 
@Raiden thank you very much for fixing the system, the most current and functional, grateful indeed, anyone who has no knowledge was catching, like me, then only gratitude!
Working perfectly.

Ruby6ZM.png
 
what is wrong?
C++:
/home/.ots/src/player.h:1378:8: error: ‘set’ in namespace ‘std’ does not name a                                                                                         template type
   std::set<uint32_t>autoLootList;
        ^
CMakeFiles/tfs.dir/build.make:119: recipe for target 'CMakeFiles/tfs.dir/src/act                                                                                        ions.cpp.o' failed
make[2]: *** [CMakeFiles/tfs.dir/src/actions.cpp.o] Error 1
CMakeFiles/Makefile2:122: recipe for target 'CMakeFiles/tfs.dir/all' failed
make[1]: *** [CMakeFiles/tfs.dir/all] Error 2
Makefile:76: recipe for target 'all' failed
make: *** [all] Error 2

It's happening the same here.

I think the problem is in:
C++:
std::set<uint32_t> autoLootList;

because:

God Of Pain!
Code:
use forward_list<uint32_t>

jgjfys.png

Fix for this?
in player.h used codes
C++:
std::unordered_set<uint32_t> autoLootList;
> No error
player.h
C++:
std::set<uint32_t> autoLootList;
> compiler error
player.h
C++:
std::forward_list<uint32_t> autoLootList;
> compiler error


go otpch.h
and add this

#include <set>
 
This is a mess, I won't point to anyone, but remember that developers who wrote this did it as a hobby and FOR FREE, okay, the code from @psychonaut have some errors, but they might be because he did this because he was bored, and coding is fun except when you have to deal with cry babies complaining about some very simple lines not working. Really guys, if you come to the C++ codes section, try to read and understand code, creating a server is not just to copy and paste other people's systems.

Now, I'm going to TRY to explain every error I think the system have.

first, psychonaut didn't post the code to register the lua functions, and you need to do that so your lua code will recognize the addloot functions.

As @flaviiojr said, on luascript.cpp search for:

Lua:
registerMethod("Player", "getFightMode", LuaScriptInterface::luaPlayerGetFightMode);

That should be your last player method if you are using a recent TFS 1.3, below that add:

Code:
registerMethod("Player", "addAutoLootItem", LuaScriptInterface::luaPlayerAddAutoLootItem);
registerMethod("Player", "removeAutoLootItem", LuaScriptInterface::luaPlayerRemoveAutoLootItem);
registerMethod("Player", "getAutoLootItem", LuaScriptInterface::luaPlayerGetAutoLootItem);
registerMethod("Player", "getAutoLootList", LuaScriptInterface::luaPlayerGetAutoLootList);

Now, go to luascript.h and search for:

Code:
static int luaPlayerGetFightMode(lua_State* L);

And add below that:

Code:
static int luaPlayerAddAutoLootItem(lua_State* L);
static int luaPlayerRemoveAutoLootItem(lua_State* L);
static int luaPlayerGetAutoLootItem(lua_State* L);
static int luaPlayerGetAutoLootList(lua_State* L);

Now, the next error is the one of people claiming that there is no loot message anymore, first there is a typo mistake on this part of code that the OP told everyone to add

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.";            }

If you read carefully, it says "if (autolooted != "" and corpse->....." the AND on C++ is &&, so you have to change that, it will look like this:

Code:
  if (autolooted != "" && 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.";            }

Now, the next mistake is, that you were told to REPLACE the line with "ss << "Loot of " << nameDescription..." so after that last if block you need to add it again but with the lootMsg variable, so one line below add:

Code:
ss << "Loot of " << nameDescription << ": " << lootMsg;

Now the last mistake is that after all those, the system at all doesn't works (it doesn't take the item), that because you where told to REPLACE the line with "corpse->internalAddThing(item);" to the following:

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);
               }

Which is wrong, what you really have to reaplce is the entire if block, so.

REPLACE:

Code:
if (g_game.internalAddItem(corpse, item) != RETURNVALUE_NOERROR) {
                    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);
               }

So your function create loot over monsters.cpp should look like this:

Code:
void MonsterType::createLoot(Container* corpse)
{
    if (g_config.getNumber(ConfigManager::RATE_LOOT) == 0) {
        corpse->startDecaying();
        return;
    }

    Player* owner = g_game.getPlayerByID(corpse->getCorpseOwner());
    std::string autolooted = "";
    if (!owner || owner->getStaminaMinutes() > 840) {
        for (auto it = info.lootItems.rbegin(), end = info.lootItems.rend(); it != end; ++it) {
            auto itemList = createLootItem(*it);
            if (itemList.empty()) {
                continue;
            }

            for (Item* item : itemList) {
                //check containers
                if (Container* container = item->getContainer()) {
                    if (!createLootContainer(container, *it)) {
                        delete container;
                        continue;
                    }
                }

                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);
                }
            }
        }

        if (owner) {
            std::ostringstream ss;
            std::string lootMsg = corpse->getContentDescription();
            //ss << "Loot of " << nameDescription << ": " << corpse->getContentDescription(); -- change for autoloot system
            if (autolooted != "" && corpse->getContentDescription() == "nothing"){
                lootMsg = autolooted.erase(0,2) + " that was autolooted";
            } else if (autolooted != ""){
                lootMsg = corpse->getContentDescription() + " and " + autolooted.erase(0,2) + " was auto looted";
            }

            ss << "Loot of " << nameDescription << ": " << lootMsg;

            if (owner->getParty()) {
                ss << " by " << owner->getName();
                owner->getParty()->broadcastPartyLoot(ss.str());
            } else {
                owner->sendTextMessage(MESSAGE_LOOT, ss.str());
            }
        }
    } else {
        std::ostringstream ss;
        ss << "Loot of " << nameDescription << ": nothing (due to low stamina)";

        if (owner->getParty()) {
            owner->getParty()->broadcastPartyLoot(ss.str());
        } else {
            owner->sendTextMessage(MESSAGE_LOOT, ss.str());
        }
    }

    corpse->startDecaying();
}

Be sure to read my post slowly and step by step to understand what you have to do, and remember, we are helping with hope to receive no more than a thanks in exchange, nobody is perfect, and nobody will like to help a crybaby just because they don't understand the code, maybe I'm missing something too, I read the whole thread and I was able to figure out how to make it works (I'm a developer, but I'm not a C++ developer).

Best regards
very good! However there is a missing condition that is enabling a possible crash ...

C++:
                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);
                }
 
-- Can not edit ...
C++:
                if (owner && 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);
                }
 
-- Can not edit ...
C++:
                if (owner && 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);
                }

As I said, maybe I'm missing something too, thank you, but, please explain why without the "owner" condition it could crash the server, I don't know if I'm being lazy but I don't get it :p
 
The player kills the creature, then dies before the function is called, but the owner has already been stored in the variable, the function will search the player and will not find..
 
It took 6 months but it is finally working here kkk

Thanks @Raiden and @flaviiojr

Now I'm gonna develop a button in OTClient that show "Enable auto loot" or "Disable auto loot" when you ctrl + click on item.

Edit: :)

34682
 
Last edited:
Back
Top