Feature Unpack items/outfits from any client to PNG with OTClient!

Joined
Sep 19, 2010
Messages
646
Best answers
0
Likes
206
Location
Cave
#21
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:
Joined
Aug 3, 2017
Messages
528
Best answers
7
Likes
16
#22
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?
 

Gesior.pl

Mega Noob&LOL 2012
Premium User
Joined
Sep 18, 2007
Messages
1,967
Best answers
17
Likes
858
Location
PLand
#23
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.
 
Joined
Aug 3, 2017
Messages
528
Best answers
7
Likes
16
#24
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?
 
Joined
Aug 3, 2017
Messages
528
Best answers
7
Likes
16
#25
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) }"
 

Gesior.pl

Mega Noob&LOL 2012
Premium User
Joined
Sep 18, 2007
Messages
1,967
Best answers
17
Likes
858
Location
PLand
#26
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?
 
Joined
Aug 3, 2017
Messages
528
Best answers
7
Likes
16
#28
-- 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
 

Yan_Liima

New Member
Joined
Jul 20, 2015
Messages
11
Best answers
0
Likes
2
#31
Is it possible to configure animated gif just one part of the front? walking
example:
28281.gif
 
Top