• 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!

Exp/Kill/Drop Tracker Module [OTCV8] [TFS 1.4.2]

This is my player.lua. I've did some prints and the item is not sent. No errors in console :/

Lua:
function Player.updateKillTracker(self, monster, corpse)
    local monsterType = monster:getType()
    if not monsterType then
        return false
    end

    local monsterOutfit = monsterType:getOutfit()

    local networkMessage = NetworkMessage()
    networkMessage:addByte(0xD1)
    networkMessage:addString(monster:getName())
    networkMessage:addU16(monsterOutfit.lookType or 19)
    networkMessage:addByte(monsterOutfit.lookHead)
    networkMessage:addByte(monsterOutfit.lookBody)
    networkMessage:addByte(monsterOutfit.lookLegs)
    networkMessage:addByte(monsterOutfit.lookFeet)
    networkMessage:addByte(monsterOutfit.lookAddons)
    networkMessage:addByte(corpse:getSize())

    print("Contents of corpse:")
    for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        networkMessage:addItem(item)
        print("Item " .. i .. ": " .. item:getName())
    end

    if self:getParty() then
        networkMessage:sendToPlayer(self:getParty():getLeader())
        local membersList = self:getParty():getMembers()
        for i = 1, #membersList do
            local player = membersList[i]
            if player then
                networkMessage:sendToPlayer(player)
            end
        end
        networkMessage:delete()
        return true
    end

    networkMessage:sendToPlayer(self)
    networkMessage:delete()
    return true
end
 
This is my player.lua. I've did some prints and the item is not sent. No errors in console :/

Lua:
function Player.updateKillTracker(self, monster, corpse)
    local monsterType = monster:getType()
    if not monsterType then
        return false
    end

    local monsterOutfit = monsterType:getOutfit()

    local networkMessage = NetworkMessage()
    networkMessage:addByte(0xD1)
    networkMessage:addString(monster:getName())
    networkMessage:addU16(monsterOutfit.lookType or 19)
    networkMessage:addByte(monsterOutfit.lookHead)
    networkMessage:addByte(monsterOutfit.lookBody)
    networkMessage:addByte(monsterOutfit.lookLegs)
    networkMessage:addByte(monsterOutfit.lookFeet)
    networkMessage:addByte(monsterOutfit.lookAddons)
    networkMessage:addByte(corpse:getSize())

    print("Contents of corpse:")
    for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        networkMessage:addItem(item)
        print("Item " .. i .. ": " .. item:getName())
    end

    if self:getParty() then
        networkMessage:sendToPlayer(self:getParty():getLeader())
        local membersList = self:getParty():getMembers()
        for i = 1, #membersList do
            local player = membersList[i]
            if player then
                networkMessage:sendToPlayer(player)
            end
        end
        networkMessage:delete()
        return true
    end

    networkMessage:sendToPlayer(self)
    networkMessage:delete()
    return true
end
Corpze size is probably equal to 0, so it wont add any items. Make sure the update player tracker is called after all items is added and not prior to.
 
Corpze size is probably equal to 0, so it wont add any items. Make sure the update player tracker is called after all items is added and not prior to.
Mine is all working, except the drop, it doesn't count the items collected, see my function as it is


Lua:
function Player.updateKillTracker(self, monster, corpse)
 local monsterType = monster:getType()
    if not monsterType then
        return false
    end

    local monsterOutfit = monsterType:getOutfit()

    local networkMessage = NetworkMessage()
    networkMessage:addByte(0xD1)
    networkMessage:addString(monster:getName())
    networkMessage:addU16(monsterOutfit.lookType or 19)
    networkMessage:addByte(monsterOutfit.lookHead)
    networkMessage:addByte(monsterOutfit.lookBody)
    networkMessage:addByte(monsterOutfit.lookLegs)
    networkMessage:addByte(monsterOutfit.lookFeet)
    networkMessage:addByte(monsterOutfit.lookAddons)
    networkMessage:addByte(corpse:getSize())

    for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        networkMessage:addItem(item)
        networkMessage:addString(item:getName())
    end

    if self:getParty() then
        networkMessage:sendToPlayer(self:getParty():getLeader())
        local membersList = self:getParty():getMembers()
        for i = 1, #membersList do
            local player = membersList[i]
            if player then
                networkMessage:sendToPlayer(player)
            end
        end
        networkMessage:delete()
        return true 
    end

    networkMessage:sendToPlayer(self)
    networkMessage:delete()
    return true
end

1715557348368.png
 
Last edited:
Mine is all working, except the drop, it doesn't count the items collected, see my function as it is


Lua:
function Player.updateKillTracker(self, monster, corpse)
 local monsterType = monster:getType()
    if not monsterType then
        return false
    end

    local monsterOutfit = monsterType:getOutfit()

    local networkMessage = NetworkMessage()
    networkMessage:addByte(0xD1)
    networkMessage:addString(monster:getName())
    networkMessage:addU16(monsterOutfit.lookType or 19)
    networkMessage:addByte(monsterOutfit.lookHead)
    networkMessage:addByte(monsterOutfit.lookBody)
    networkMessage:addByte(monsterOutfit.lookLegs)
    networkMessage:addByte(monsterOutfit.lookFeet)
    networkMessage:addByte(monsterOutfit.lookAddons)
    networkMessage:addByte(corpse:getSize())

    for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        networkMessage:addItem(item)
        networkMessage:addString(item:getName())
    end

    if self:getParty() then
        networkMessage:sendToPlayer(self:getParty():getLeader())
        local membersList = self:getParty():getMembers()
        for i = 1, #membersList do
            local player = membersList[i]
            if player then
                networkMessage:sendToPlayer(player)
            end
        end
        networkMessage:delete()
        return true
    end

    networkMessage:sendToPlayer(self)
    networkMessage:delete()
    return true
end

View attachment 84609

You have to investigate the corpse size. If its 0 you wont get any loot drops.
This can be due to player:updateKillTracker is called before any loot is added to the corpse. Try add the method in the onDrop that are actually setting the loot.(Scripts/eventcallback/monster/default_monsterOnDrop…)
 
Exactly as @Klank said, you have to call function updateKillTracker after the loot is added, otherwise you will get corpse size equal 0. Everything works perfectly. Great module.
 
You have to investigate the corpse size. If its 0 you wont get any loot drops.
This can be due to player:updateKillTracker is called before any loot is added to the corpse. Try add the method in the onDrop that are actually setting the loot.(Scripts/eventcallback/monster/default_monsterOnDrop…)
Hey Klank, I've another issue here.. Kill tracker is not reading items that drops inside a container, like a bag. How to make it work?
 
Hey Klank, I've another issue here.. Kill tracker is not reading items that drops inside a container, like a bag. How to make it work?
then you have to «unpack» the bag, list them out and send it in the update killtracker. How? I dont know, Im not able to test this out for a period. Its not compatible with the old loot systems how it is now.
 
then you have to «unpack» the bag, list them out and send it in the update killtracker. How? I dont know, Im not able to test this out for a period. Its not compatible with the old loot systems how it is now.
I've tried this

in Player.UpdateKillTracker

Lua:
for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        if item:isContainer() then
            networkMessage:addByte(item:getSize())
            for j = item:getSize() - 1, 0, -1 do
                local containerItem = item:getItem(j)
                networkMessage:addItem(containerItem)
                networkMessage:addString(containerItem:getName()) --- ADD THIS
            end
        else
            networkMessage:addItem(item)
            networkMessage:addString(item:getName()) --- ADD THIS
        end
    end

But I get errors in Otclient , I know I must add some lines on parseKillTracker but i'm stuck in this part
 
I've tried this

in Player.UpdateKillTracker

Lua:
for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        if item:isContainer() then
            networkMessage:addByte(item:getSize())
            for j = item:getSize() - 1, 0, -1 do
                local containerItem = item:getItem(j)
                networkMessage:addItem(containerItem)
                networkMessage:addString(containerItem:getName()) --- ADD THIS
            end
        else
            networkMessage:addItem(item)
            networkMessage:addString(item:getName()) --- ADD THIS
        end
    end

But I get errors in Otclient , I know I must add some lines on parseKillTracker but i'm stuck in this part
Try this, I specified only to be the ID for the usual loot bag since I want to avoid not listing other containers that may be dropped.

Lua:
    for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        if itemId == 1987 then
            for _, innerItem in pairs(item:getItems()) do
                networkMessage:addItem(innerItem)
                networkMessage:addString(innerItem:getName())
            end
        else
            networkMessage:addItem(item)
            networkMessage:addString(item:getName())
        end
    end
 
Try this, I specified only to be the ID for the usual loot bag since I want to avoid not listing other containers that may be dropped.

Lua:
    for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        if itemId == 1987 then
            for _, innerItem in pairs(item:getItems()) do
                networkMessage:addItem(innerItem)
                networkMessage:addString(innerItem:getName())
            end
        else
            networkMessage:addItem(item)
            networkMessage:addString(item:getName())
        end
    end
That was a nice try, but I get this error when the bag has 2 or more items inside it
 

Attachments

That was a nice try, but I get this error when the bag has 2 or more items inside it
Its because the corpse size used in client side is less then the number of items sent. You would also need to increase corpse size to the additional number of items inside the bag.
 
Its because the corpse size used in client side is less then the number of items sent. You would also need to increase corpse size to the additional number of items inside the bag.
How to make this on client side?
 
I've tried this

in Player.UpdateKillTracker

Lua:
for i = corpse:getSize() - 1, 0, -1 do
        local item = corpse:getItem(i)
        if item:isContainer() then
            networkMessage:addByte(item:getSize())
            for j = item:getSize() - 1, 0, -1 do
                local containerItem = item:getItem(j)
                networkMessage:addItem(containerItem)
                networkMessage:addString(containerItem:getName()) --- ADD THIS
            end
        else
            networkMessage:addItem(item)
            networkMessage:addString(item:getName()) --- ADD THIS
        end
    end

But I get errors in Otclient , I know I must add some lines on parseKillTracker but i'm stuck in this part
If u check rookie i have node js that takes items out of bags in monster files needed it for rarity system to work that way
 
How to make this on client side?

You dont need to edit client side.
Another way to do it, is to remove the bag from the corpse, add the items to the corpse before you loop it and check for corpze size, when you done, you remove the items and add the bag back in after the network msges has been sent.

Prob even easier way to do it, but im not able to dig in.

Your problem is that corpze size, as you do it now, is lower than the number of network msges you send, hence the terminal error. Client is receiving more «items/msges» than it expects.
 
JavaScript:
const fs = require('fs');
const path = require('path');
const xml2js = require('xml2js');

const folderPath = './'; // Change this to the path of your folder

// Function to process a single XML file
function processFile(filePath) {
    fs.readFile(filePath, 'utf-8', (err, data) => {
        if (err) {
            console.error('Error reading file:', err);
            return;
        }

        // Parse XML to JSON
        xml2js.parseString(data, (err, result) => {
            if (err) {
                console.error(`Error parsing XML in file ${filePath}:`, err);
                return;
            }

            // Move items from inside <inside> to just before </loot>
            if (result.monster && result.monster.loot && result.monster.loot[0] && result.monster.loot[0].item) {
                const itemsInside = result.monster.loot[0].item.filter(item => item.inside);
                itemsInside.forEach(itemInside => {
                    const itemsToMove = itemInside.inside[0].item;
                    delete itemInside.inside;
                    const lootIndex = result.monster.loot[0].item.findIndex(item => item === itemInside);
                    result.monster.loot[0].item.splice(lootIndex, 0, ...itemsToMove);
                });
            }

            // Convert JSON back to XML
            const builder = new xml2js.Builder();
            const modifiedXml = builder.buildObject(result);

            // Write modified XML back to file
            fs.writeFile(filePath, modifiedXml, err => {
                if (err) {
                    console.error('Error writing file:', err);
                    return;
                }
                console.log(`Modified XML file saved as ${filePath}`);
            });
        });
    });
}

// Function to process all XML files in a folder and its subfolders
function processFolder(folderPath) {
    fs.readdir(folderPath, (err, files) => {
        if (err) {
            console.error('Error reading folder:', err);
            return;
        }

        files.forEach(file => {
            const filePath = path.join(folderPath, file);
            if (fs.statSync(filePath).isFile() && path.extname(filePath) === '.xml') {
                processFile(filePath);
            } else if (fs.statSync(filePath).isDirectory()) {
                processFolder(filePath); // Recursively process subdirectories
            }
        });
    });
}

// Start processing the folder
processFolder(folderPath);
here u go this will take all monsters.xml files and take out items from <inside> but leave the bag for lootbags
use nodejs also remember to make all corpse size bigger!
 
Back
Top