• 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 Unpack items/outfits from any client to PNG with OTClient!

yes, and those files are for outfits

Added item/outfit generator to sources (you can use binary file v3 to unpack outfits/items):

(from that other thread, and it's what I used to display custom outfits on ascalon-world.com)
 
Last edited by a moderator:
This is little C++ code for OTClient to unpack items/outfits. This is code/tutorial for advanced OTS users!
With this code/tutorial you can unpack items/outfits images from your tibia version/your custom client .spr/.otb!


First you need to compile OTClient (edubart/otclient) and this is not part of this tutorial.
I compiled it on linux and windows without any problems with this tutorial:
edubart/otclient


1. In src/client/thingtype.cpp find:
Code:
void ThingType::exportImage(std::string fileName)
{
   (here content of function)
}
and replace with:
Code:
void ThingType::exportImage(std::string fileName, int type)
{
    /* types:
    0 - normal export
    1 - outfit export, all animation frames
    2 - outfit export, only first animation frame
    3 - items export, first frame of animation
    */
    if(m_null)
        stdext::throw_exception("cannot export null thingtype");

    if(m_spritesIndex.size() == 0)
        stdext::throw_exception("cannot export thingtype without sprites");
    if(type == 0)
    {
        /* ORGINAL CODE */
        ImagePtr image(new Image(Size(32 * m_size.width() * m_layers * m_numPatternX, 32 * m_size.height() * m_animationPhases * m_numPatternY * m_numPatternZ)));
        for(int z = 0; z < m_numPatternZ; ++z) {
            for(int y = 0; y < m_numPatternY; ++y) {
                for(int x = 0; x < m_numPatternX; ++x) {
                    for(int l = 0; l < m_layers; ++l) {
                        for(int a = 0; a < m_animationPhases; ++a) {
                            for(int w = 0; w < m_size.width(); ++w) {
                                for(int h = 0; h < m_size.height(); ++h) {
                                    image->blit(Point(32 * (m_size.width() - w - 1 + m_size.width() * x + m_size.width() * m_numPatternX * l),
                                                      32 * (m_size.height() - h - 1 + m_size.height() * y + m_size.height() * m_numPatternY * a + m_size.height() * m_numPatternY * m_animationPhases * z)),
                                                g_sprites.getSpriteImage(m_spritesIndex[getSpriteIndex(w, h, l, x, y, z, a)]));
                                }
                            }
                        }
                    }
                }
            }
        }

        image->savePNG(fileName);
    }
    else if(type == 1)
    {
        /* OUTFITS ANIM */
        /*
        patternX = direction
        patternY = 0/1/2 = addon none/first/second
        patternZ = 0/1 = is sitting on mount no/yes
        layer = 0/1 = biala postac / co jak wypelniac
        */
        g_resources.makeDir("outfits_anim");
        g_resources.makeDir(stdext::format("outfits_anim/%d",getId()));
        for(int z = 0; z < m_numPatternZ; ++z) {
            for(int y = 0; y < m_numPatternY; ++y) {
                for(int x = 0; x < m_numPatternX; ++x) {
                    for(int l = 0; l < m_layers; ++l) {
                        for(int a = 0; a < m_animationPhases; ++a) {
                            ImagePtr image(new Image(Size(32 * m_size.width(), 32 * m_size.height())));
                            for(int w = 0; w < m_size.width(); ++w) {
                                for(int h = 0; h < m_size.height(); ++h) {
                                    image->blit(Point(32 * (m_size.width() - w - 1), 32 * (m_size.height() - h - 1)), g_sprites.getSpriteImage(m_spritesIndex[getSpriteIndex(w, h, l, x, y, z, a)]));
                                }
                            }
                            if(l == 1)
                                image->savePNG(stdext::format("outfits_anim/%d/%d_%d_%d_%d_template.png",getId(),a+1,z+1,y+1,x+1));
                            else
                                image->savePNG(stdext::format("outfits_anim/%d/%d_%d_%d_%d.png",getId(),a+1,z+1,y+1,x+1));
                        }
                    }
                }
            }
        }
    }
    else if(type == 2)
    {
        /* OUTFITS NO ANIM */
        /*
        patternX = direction
        patternY = 0/1/2 = addon none/first/second
        patternZ = 0/1 = is sitting on mount no/yes
        layer = 0/1 = biala postac / co jak wypelniac
        */
        g_resources.makeDir("outfits_no_anim");
        g_resources.makeDir(stdext::format("outfits_no_anim/%d",getId()));
        for(int z = 0; z < m_numPatternZ; ++z) {
            for(int y = 0; y < m_numPatternY; ++y) {
                for(int x = 0; x < m_numPatternX; ++x) {
                    for(int l = 0; l < m_layers; ++l) {
                        ImagePtr image(new Image(Size(32 * m_size.width(), 32 * m_size.height())));
                        for(int w = 0; w < m_size.width(); ++w) {
                            for(int h = 0; h < m_size.height(); ++h) {
                                image->blit(Point(32 * (m_size.width() - w - 1), 32 * (m_size.height() - h - 1)), g_sprites.getSpriteImage(m_spritesIndex[getSpriteIndex(w, h, l, x, y, z, 0)]));
                            }
                        }
                        if(l == 1)
                            image->savePNG(stdext::format("outfits_no_anim/%d/%d_%d_%d_%d_template.png",getId(),1,z+1,y+1,x+1));
                        else
                            image->savePNG(stdext::format("outfits_no_anim/%d/%d_%d_%d_%d.png",getId(),1,z+1,y+1,x+1));
                    }
                }
            }
        }
    }
    else if(type == 3)
    {
        /* ITEMS */
        g_resources.makeDir("items");

        ImagePtr image(new Image(Size(32 * m_size.width(), 32 * m_size.height())));
        for(int l = 0; l < m_layers; ++l) {
            for(int w = 0; w < m_size.width(); ++w) {
                for(int h = 0; h < m_size.height(); ++h) {
                image->blit(Point(32 * (m_size.width() - w - 1), 32 * (m_size.height() - h - 1)),
                    g_sprites.getSpriteImage(m_spritesIndex[getSpriteIndex(w, h, l, 0, 0, 0, 0)]));
                }
            }
        }
        image->savePNG(stdext::format("items/%s.png", fileName));
    }
}

1.1 At begining of file add:
Code:
#include <framework/core/resourcemanager.h>

2. In src/client/thingtype.h find:
Code:
void exportImage(std::string fileName);
and replace with:
Code:
void exportImage(std::string fileName, int type = 0);

3. Rebuild project.

C++ PART IS DONE!

Now LUA/client part.

EXAMPLE FOR TIBIA 10.76

1. Copy Tibia [tibia.com] client Tibia.dat and Tibia.spr to data/things/1076/Tibia.dat and data/things/1076/Tibia.spr
2. Copy OTS (make sure it's 10.76 OTS!) data/items/items.otb to OTClient data/things/1076/items.otb

-------------------------
3. Run OTClient.exe
4. At top of client window is small black icon that opens 'console'. Click it! :)
5. Tell (paste in console and press ENTER) OTClient where are files and what tibia version it is:
Code:
g_game.setClientVersion(1076) g_things.loadDat('things/1076/Tibia.dat') g_things.loadOtb('things/1076/items.otb') g_sprites.loadSpr('things/1076/Tibia.spr')
6. Choose what you want to unpack and paste code (when you paste it in console, it will be all in 1 line, just press ENTER, it will work!):
6.1. OUTFITS, with all animation frames
Code:
for i,v in pairs(g_things.getThingTypes(1)) do
    if(v and v:getId() > 0) then
        outfit = g_things.getThingType(v:getId(),1)
        outfit:exportImage(v:getId(), 1)
    end
end
6.2 OUTFITS, just first frame of animation
Code:
for i,v in pairs(g_things.getThingTypes(1)) do
    if(v and v:getId() > 0) then
        outfit = g_things.getThingType(v:getId(),1)
        outfit:exportImage(v:getId(), 2)
    end
end
6.3 ITEMS, first frame of animation, count = 1
Code:
for i,v in pairs(g_things.getThingTypes(0)) do
    if(v and v:getId() > 0) then
        itemOtb = g_things.findItemTypeByClientId(v:getId())
        if(itemOtb and itemOtb:getClientId() > 0) then
            item = g_things.getThingType(itemOtb:getClientId(),0)
            if(item and item:getId() > 0) then
                item:exportImage(itemOtb:getServerId(), 3)
            end
        end
    end
end
--------------------------------------
Now client will freez for few seconds/minutes.. client unfreez, but where are my images?

Windows: C:\Users\yourWindowsUserName\otclient\
[THERE WILL BE YOUR WINDOWS 'language' NAME FOR 'USERS' folder]
Linux: /home/yourUserName/.otclient/

Script will create folders:
items, outfits_no_anim, outfits_anim

Files in these folders are in format compatible with outfit generator/Gesior acc. maker images folder.
how I can open otclient? I compilled but my computer asks how I want to open otclient: is it like it's not an application, what Im doing wrong?
 
On windows it should create otclient.exe file. On linux it creates 'otclient' file. You can run it by console ./otclient. Maybe you need to use 'chmod +x otclient' to make it 'executable' and then run in system GUI.
 
On windows it should create otclient.exe file. On linux it creates 'otclient' file. You can run it by console ./otclient. Maybe you need to use 'chmod +x otclient' to make it 'executable' and then run in system GUI.
thanks, worked!!


but about outfit.data.txt, how can we generate this file, must it be manually?
 
I generated the pngs and still appear: "Outfit does not exist or file cache is not generated."
So I entered the link cacheGenerator with my password and appear: "array(7) { [8]=> int(546) [3]=> int(252) [5]=> int(2) [4]=> int(12) [2]=> int(11) [6]=> int(3) [1]=> int(7) }"
 
I generated the pngs and still appear: "Outfit does not exist or file cache is not generated."
So I entered the link cacheGenerator with my password and appear: "array(7) { [8]=> int(546) [3]=> int(252) [5]=> int(2) [4]=> int(12) [2]=> int(11) [6]=> int(3) [1]=> int(7) }"
So new outfits work for you?
 
-- FIRST POST WAS TOO LONG --
----------------------------------------------
--------------------------------------
Format:
Items folder is full of XXXX.png files, XXXX - OTS item ID

Outfit folder name = outfit ID.
Outfit file names are like:
X_Y_Z_O.png
X - frame ID (from 1 up to 8 [not all creatures have 8 frames of animation])
Y - mount: 1 - not on mount, 2 - on mount
Z - addon: 1 - none, 2 - first, 3 - second [there is a special method how to compose these 3 images [none + first + second] into one .png, PHP code is in my forum outfit thread, in .zip]
O - direction (1 - 4)
--------------------------------------
If you want to convert all item PNG images into GIF images it's simpliest possible PHP code to do it. You just need webserver and 2 folders:
Code:
<?php
$from = 'items'; // images PNG folder
$to = 'gif'; // empty folder
function png2gif($pngs, $background = array(255, 255, 255), $dest = 'gif')
{
    // by WebReflection
    foreach($pngs as $png){
        $size = getimagesize($png);
        $img = imagecreatefrompng($png);
        $image = imagecreatetruecolor($width = $size[0], $height = $size[1]);
        imagefill($image, 0, 0, $bgcolor = imagecolorallocate($image, $background[0], $background[1], $background[2]));
        imagecopyresampled($image, $img, 0, 0, 0, 0, $width, $height, $width, $height);
        imagecolortransparent($image, $bgcolor);
        imagegif($image, str_ireplace('.png', '.gif', $dest.DIRECTORY_SEPARATOR.basename($png)), 100);
        imagedestroy($image);
    }
}
png2gif(glob($from . "/*.png"), $background = array(255, 255, 255), $to);

EDIT:
updated PHP code, now change PNG to GIF with transparent backgrounds!

Hey, I did it but dont converted to gif, my page with this script appear blank and folder gif have nothing inside
Ps. I have folder items with many images png inside, both folders with chmod 777 -R
 
Hey, I did it but dont converted to gif, my page with this script appear blank and folder gif have nothing inside
Ps. I have folder items with many images png inside, both folders with chmod 777 -R
worked, sorry, thanks!
 
Someone asked in this thread, if it's possible to export 'effect' animations, but he posted it in Portuguese and message has been deleted.
I answered - in English - I will try to make it on Tuesday, but my answer was also deleted.

Anyway, now it's possible. Generator is available here:
It will generate effects.zip file with .png images. To convert them to animated .gifs, you need to upload that effects.zip to:
 
Someone asked in this thread, if it's possible to export 'effect' animations, but he posted it in Portuguese and message has been deleted.
I answered - in English - I will try to make it on Tuesday, but my answer was also deleted.

Anyway, now it's possible. Generator is available here:
It will generate effects.zip file with .png images. To convert them to animated .gifs, you need to upload that effects.zip to:
Thankssss
 

Similar threads

Back
Top