looking who can make new Suit

10/30/2022 11:02 jr1#1
hello , Anyone here know who can make new suit? for twelvesky 2.8?
10/30/2022 16:33 lnwnuyhodd#2
make new suit = Create a new 3D model?
make new suit = Add an existing suit from version 2.8?
10/30/2022 23:45 migisenpai#3
Quote:
Originally Posted by lnwnuyhodd View Post
make new suit = Create a new 3D model?
make new suit = Add an existing suit from version 2.8?
They are using 2.5 origin. Not 2.8 gxcw. They mistake 2.5 origin for "2.8"

Anyway. Methods to "create" suit is

1. Replace existing costume sobject with other costume sobject from different client. (Chinese 2.8 gxcw costume should also work for 2.5 cli)
2. Hook client avatar object draw, gimage init
10/31/2022 03:06 lnwnuyhodd#4
Code:
if( !(make new suit = Add an existing suit from version 2.8) )
  return;
You must have an understanding of IDA or other debug programs and C++ skills to do this.
if you understand it it was easy.

1.hook right click item function
Code:
class INVENUI
{
public:
	INVENUI(){}
	static BOOL INVENUI::AskUseItem(int mX, int mY)
	{
		//Hook and Call Original function
		//BOOL INVENUI::AskUseItem(INVENUI* This, int mX, int mY);
		//INVENUI* This = 0x??????;
		BOOL res = ori_INVENUI_AskUseItem(This, mX, mY);
		if( !res )
			return 0;
		
		ITEM_INFO *a1 = ITEM::Search(mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][0]);
		if ( !a1 )
			return 1;

		int k;
	  
		switch( a1->iIndex )
		{
		case new_costume_id:
			if (a1->iIndex % 3 != (mMYINFO[0].mUseAvatar.aPreviousTribe + 1) % 3)
			{
				BASICUI::Insert1(1521);
				return 1;
			}
			
			for (k = 0; k < 10; ++k)
			{
				if (a1->iIndex == mMYINFO[0].mUseAvatar.aCostume[k])
				{
					BASICUI::Insert1(1514);
					return 1;
				}
				if (!mMYINFO[0].mUseAvatar.aCostume[k])
					break;
			}
			if (k == 10)
			{
				BASICUI::Insert1(1516);
				return 1;
			}
	
			GSOUND::Play(&mGDATA[0].mSOUND_05[2], 0, 100, 1);
			mMYINFO[0].mUseInventoryPage = tPage;
			mMYINFO[0].mUseInventoryIndex = tIndex;
			CBOXUI::Set(7, 1522, aEmptyChar);
	
			break;
		}

		return 1;
	}
};
1.1.add gimage/002 for item image

2.hook W_USE_INVENTORY_ITEM_RECV
Code:
#define MAX_NETWORK_BUFFER_SIZE										200000
class NETWORK
{
public:
	BOOL mCheckInitForNetwork;
	char mPacketEncryptionValue[4];
	BOOL mCheckConnectState;
	SOCKET mSocket;
	SOCKADDR_IN mAddress;
	BYTE mBuffer[MAX_NETWORK_BUFFER_SIZE];
	int mBufferSize;
};

NETWORK* mNETWORK = 0x?????;

#define SetInv( tPage, tIndex, v0, v1, v2, v3, v4, v5 ) \
{ \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][0] = v0; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][1] = v1; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][2] = v2; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][3] = v3; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][4] = v4; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][5] = v5; \
}
#define SetInvSock( tPage, tIndex, v0, v1, v2 )  \
{ \
    mMYINFO[0].mUseAvatar.aInvenSocket[tPage][tIndex][0] = v0; \
    mMYINFO[0].mUseAvatar.aInvenSocket[tPage][tIndex][1] = v1; \
    mMYINFO[0].mUseAvatar.aInvenSocket[tPage][tIndex][2] = v2; \
}
#define ClearInv( tPage, tIndex )  \
{ \
    SetInv( tPage, tIndex, 0, 0, 0, 0, 0, 0 ); \
    SetInvSock( tPage, tIndex, 0, 0, 0 ); \
}

void W_USE_INVENTORY_ITEM_RECV()
{
    int tResult, tPage, tIndex, tValue;

    CopyMemory(&tResult, &mNETWORK[0].mBuffer[1], 4);
    CopyMemory(&tPage, &mNETWORK[0].mBuffer[5], 4);
    CopyMemory(&tIndex, &mNETWORK[0].mBuffer[9], 4);
    CopyMemory(&tValue, &mNETWORK[0].mBuffer[13], 4);  

    ITEM_INFO* a1 = ITEM::Search(mMYINFO[0].mUseAvatar.aInventory[tPage % 100][tIndex % 100][0]);
	if ( !a1 )
		return;
	switch( a1->iIndex )
	{
	case new_costume_id:    
		if (tResult)
		{
			BASICUI::Insert1(1869);
		}
		else
		{
			mMYINFO[0].mUseAvatar.aCostume[tValue] = tITEM_INFO->iIndex;
			ClearInv( tPage, tIndex );
			GSOUND::Play(&mGDATA[0].mSOUND_05[296], 0, 100, 1);
			BASICUI::Insert1(1517);
		}
		return;
	}

	//Hook and call Original function
	//void W_USE_INVENTORY_ITEM_RECV();
	ori_W_USE_INVENTORY_ITEM_RECV(); 
}
3.create GSOBJECT/GMOTION class
Code:
namespace TW2AddIn
{

class SKIN2_FOR_GXD
{
public:
	BYTE data[0x378];
};

class SOBJECT2_FOR_GXD
{
public:
	BOOL mCheckValidState;
	int mSkinNum;
	SKIN2_FOR_GXD *mSkin;
  
	SOBJECT2_FOR_GXD()
	{
		Init();
	}
	void Init()
	{
		this->mCheckValidState = 0;
		this->mSkinNum = 0;
		this->mSkin = 0;
	}
	void Free()
	{
		//Hook and Call Original function
		//void TW2AddIn::SOBJECT2_FOR_GXD::Free(TW2AddIn::SOBJECT2_FOR_GXD* This);
		ori_TW2AddIn_SOBJECT2_FOR_GXD_Free(this);
	}
};


class MOTION2_FOR_GXD
{
public:
	BOOL mCheckValidState;
	int mFrameNum;
	int mBoneNum;
	D3DXMATRIX *mKeyMatrix;
	
	MOTION2_FOR_GXD()
	{
		Init();
	}
	void Init()
	{
	    this->mCheckValidState = 0;
		this->mKeyMatrix = 0;
	}
	void Free()
	{
		//Hook and Call Original function
		//void TW2AddIn::MOTION2::FOR_GXD::Free(MOTION2_FOR_GXD* This);
		ori_TW2AddIn_MOTION2_FOR_GXD_Free(this);
	}
};


}


class GMOTION
{
public:
	BOOL mCheckFrameNum;
	char mFileName[100];
	int mFrameNum;
	float mLastUsedTime;
	CRITICAL_SECTION mLock;
	TW2AddIn::MOTION2_FOR_GXD mDATA;
	BOOL mCheckValidState;
};


class GSOBJECT
{
public:
	BOOL mCheckValidState;
	char mFileName[100];
	TW2AddIn::SOBJECT2_FOR_GXD mDATA;
	float mLastUsedTime;
	CRITICAL_SECTION mCritical;
  
	GSOBJECT()
	{
		Init();
		InitializeCriticalSection(&this->mCritical);
	}
	void Init()
	{
		this->mCheckValidState = FALSE;
		this->mFileName[0] = 0;
		this->mDATA.mCheckValidState = FALSE;
	}
	void Free()
	{
	    EnterCriticalSection(&this->mCritical);
		this->mCheckValidState = 0;
		this->mDATA.Free();
		LeaveCriticalSection(&this->mCritical);
	}
	
	void DisplaySObject(int tDrawSort, float pFrame, float *tL, float tYAngle, float tHeightForCulling, GMOTION *tMOTION, BOOL tLoadSort)
	{
		//Hook and Call Original function
		//void GSOBJECT::DisplaySObject(GSOBJECT* This, int tDrawSort, float pFrame, float *tL, float tYAngle, float tHeightForCulling, GMOTION *tMOTION, BOOL tLoadSort);
		ori_GSOBJECT_DisplaySObject(this, tDrawSort, pFrame, tL, tYAngle, tHeightForCulling, tMOTION, tLoadSort);
	}
};


//initialize new object
GSOBJECT new_gsobject;

//init mFileName
sprintf( new_gsobject.mFileName, "%s", "G03_GDATA\\D04_GSOBJECT\\010\\A%03d001%03d.SOBJECT", 1, 28 );
4.Use GSOBJECT and Hook AVATAR_OBJECT:: Draw
Code:
class UTIL
{
public:
	static BOOL CheckPossibleDrawMeWithCamera(float tCoord[3], float tLength)
	{
		//Hook and Call Original function
		BOOL res = ori_UTIL_CheckPossibleDrawMeWithCamera(  );
		return res;
		
		//float v3; // [esp+8h] [ebp-Ch]
		//float v4; // [esp+10h] [ebp-4h]
		//v4 = (mGXD[0].mCameraEye.z - tCoord[2]) * (mGXD[0].mCameraEye.z - tCoord[2]) + (mGXD[0].mCameraEye.y - (tLength * 0.5 + tCoord[1])) * (mGXD[0].mCameraEye.y - (tLength * 0.5 + tCoord[1])) + (mGXD[0].mCameraEye.x - *tCoord) * (mGXD[0].mCameraEye.x - *tCoord);
		//v3 = sqrt(v4);
		//return v3 >= 10.0f;
	}
}

class GDATA
{
public:
	static GMOTION* ReturnCharacterMotion(int aPreviousTribe, int aGender, int aType, int aSort, int aLevel1, int aLevel2, int aAnimalNumber)
	{
		//Hook and Call Original function
		GMOTION* res = ori_GDATA_ReturnCharacterMotion(aPreviousTribe, aGender, aType, aSort, aLevel1, aLevel2, aAnimalNumber);
		return res;
	}
};

class AVATAR_OBJECT
{
public:

	BOOL mCheckValidState;
	DWORD mServerIndex;
	DWORD mUniqueNumber;
	float mUpdateTime;
	float mUpdateTimeForRageTime;
	float mUpdateTime3;
	OBJECT_FOR_AVATAR mDATA;	
	BYTE data[1];//other unknow data
	
	//find and hook this function
	static void Draw( AVATAR_OBJECT* This, int tDrawSort, int tObjIndex, float dTime )
	{
		BOOL isLocalClient = tObjIndex == 0;
		GMOTION *tMOTION;
		
		if ( !This->mCheckValidState || tDrawSort < 1 || tDrawSort > 2 || !This->mDATA.aVisibleState || !UTIL::CheckPossibleDrawMeWithCamera(This->mDATA.aAction.aLocation, 20.0f) )
			return;
		
		int tAnimalNumber = 0;
		if ( !This->mDATA.aAnimalAbsorbState )
			tAnimalNumber = This->mDATA.aAnimalNumber;			
		tMOTION = GDATA::ReturnCharacterMotion(This->mDATA.aPreviousTribe, This->mDATA.aGender, This->mDATA.aAction.aType, This->mDATA.aAction.aSort, This->mDATA.aLevel1, This->mDATA.aLevel2, tAnimalNumber);
				
		if( This->mDATA.aCostume == new_costume_id ) {
			new_gsobject.DisplaySObject( tDrawSort, This->mDATA.aAction.aFrame, This->mDATA.aAction.aLocation, This->mDATA.aAction.aFront, 20.0f, tMOTION, isLocalClient );
		}
	}
};
Code:
on exit dll function
void dll_exit()
{
	new_gsobject.Free();
}
10/31/2022 10:16 zahter55#5
@[Only registered and activated users can see links. Click Here To Register...] can u pls say something about existing other systems. Like bottle system. Why is that slipping rows on every log in? Bottle1 878 price1 30 bottle2 879 price2 30 for example in game but after relogin it shows bottle and price1 is 0 but bottle+price2 and 3 gets new value.
10/31/2022 10:28 kapgankaan#6
Quote:
Originally Posted by lnwnuyhodd View Post
Code:
if( !(make new suit = Add an existing suit from version 2.8) )
  return;
You must have an understanding of IDA or other debug programs and C++ skills to do this.
if you understand it it was easy.

1.hook right click item function
Code:
class INVENUI
{
public:
	INVENUI(){}
	static BOOL INVENUI::AskUseItem(int mX, int mY)
	{
		//Hook and Call Original function
		//BOOL INVENUI::AskUseItem(INVENUI* This, int mX, int mY);
		//INVENUI* This = 0x??????;
		BOOL res = ori_INVENUI_AskUseItem(This, mX, mY);
		if( !res )
			return 0;
		
		ITEM_INFO *a1 = ITEM::Search(mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][0]);
		if ( !a1 )
			return 1;

		int k;
	  
		switch( a1->iIndex )
		{
		case new_costume_id:
			if (a1->iIndex % 3 != (mMYINFO[0].mUseAvatar.aPreviousTribe + 1) % 3)
			{
				BASICUI::Insert1(1521);
				return 1;
			}
			
			for (k = 0; k < 10; ++k)
			{
				if (a1->iIndex == mMYINFO[0].mUseAvatar.aCostume[k])
				{
					BASICUI::Insert1(1514);
					return 1;
				}
				if (!mMYINFO[0].mUseAvatar.aCostume[k])
					break;
			}
			if (k == 10)
			{
				BASICUI::Insert1(1516);
				return 1;
			}
	
			GSOUND::Play(&mGDATA[0].mSOUND_05[2], 0, 100, 1);
			mMYINFO[0].mUseInventoryPage = tPage;
			mMYINFO[0].mUseInventoryIndex = tIndex;
			CBOXUI::Set(7, 1522, aEmptyChar);
	
			break;
		}

		return 1;
	}
};
1.1.add gimage/002 for item image

2.hook W_USE_INVENTORY_ITEM_RECV
Code:
#define MAX_NETWORK_BUFFER_SIZE										200000
class NETWORK
{
public:
	BOOL mCheckInitForNetwork;
	char mPacketEncryptionValue[4];
	BOOL mCheckConnectState;
	SOCKET mSocket;
	SOCKADDR_IN mAddress;
	BYTE mBuffer[MAX_NETWORK_BUFFER_SIZE];
	int mBufferSize;
};

NETWORK* mNETWORK = 0x?????;

#define SetInv( tPage, tIndex, v0, v1, v2, v3, v4, v5 ) \
{ \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][0] = v0; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][1] = v1; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][2] = v2; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][3] = v3; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][4] = v4; \
    mMYINFO[0].mUseAvatar.aInventory[tPage][tIndex][5] = v5; \
}
#define SetInvSock( tPage, tIndex, v0, v1, v2 )  \
{ \
    mMYINFO[0].mUseAvatar.aInvenSocket[tPage][tIndex][0] = v0; \
    mMYINFO[0].mUseAvatar.aInvenSocket[tPage][tIndex][1] = v1; \
    mMYINFO[0].mUseAvatar.aInvenSocket[tPage][tIndex][2] = v2; \
}
#define ClearInv( tPage, tIndex )  \
{ \
    SetInv( tPage, tIndex, 0, 0, 0, 0, 0, 0 ); \
    SetInvSock( tPage, tIndex, 0, 0, 0 ); \
}

void W_USE_INVENTORY_ITEM_RECV()
{
    int tResult, tPage, tIndex, tValue;

    CopyMemory(&tResult, &mNETWORK[0].mBuffer[1], 4);
    CopyMemory(&tPage, &mNETWORK[0].mBuffer[5], 4);
    CopyMemory(&tIndex, &mNETWORK[0].mBuffer[9], 4);
    CopyMemory(&tValue, &mNETWORK[0].mBuffer[13], 4);  

    ITEM_INFO* a1 = ITEM::Search(mMYINFO[0].mUseAvatar.aInventory[tPage % 100][tIndex % 100][0]);
	if ( !a1 )
		return;
	switch( a1->iIndex )
	{
	case new_costume_id:    
		if (tResult)
		{
			BASICUI::Insert1(1869);
		}
		else
		{
			mMYINFO[0].mUseAvatar.aCostume[tValue] = tITEM_INFO->iIndex;
			ClearInv( tPage, tIndex );
			GSOUND::Play(&mGDATA[0].mSOUND_05[296], 0, 100, 1);
			BASICUI::Insert1(1517);
		}
		return;
	}

	//Hook and call Original function
	//void W_USE_INVENTORY_ITEM_RECV();
	ori_W_USE_INVENTORY_ITEM_RECV(); 
}
3.create GSOBJECT/GMOTION class
Code:
namespace TW2AddIn
{

class SKIN2_FOR_GXD
{
public:
	BYTE data[0x378];
};

class SOBJECT2_FOR_GXD
{
public:
	BOOL mCheckValidState;
	int mSkinNum;
	SKIN2_FOR_GXD *mSkin;
  
	SOBJECT2_FOR_GXD()
	{
		Init();
	}
	void Init()
	{
		this->mCheckValidState = 0;
		this->mSkinNum = 0;
		this->mSkin = 0;
	}
	void Free()
	{
		//Hook and Call Original function
		//void TW2AddIn::SOBJECT2_FOR_GXD::Free(TW2AddIn::SOBJECT2_FOR_GXD* This);
		ori_TW2AddIn_SOBJECT2_FOR_GXD_Free(this);
	}
};


class MOTION2_FOR_GXD
{
public:
	BOOL mCheckValidState;
	int mFrameNum;
	int mBoneNum;
	D3DXMATRIX *mKeyMatrix;
	
	MOTION2_FOR_GXD()
	{
		Init();
	}
	void Init()
	{
	    this->mCheckValidState = 0;
		this->mKeyMatrix = 0;
	}
	void Free()
	{
		//Hook and Call Original function
		//void TW2AddIn::MOTION2::FOR_GXD::Free(MOTION2_FOR_GXD* This);
		ori_TW2AddIn_MOTION2_FOR_GXD_Free(this);
	}
};


}


class GMOTION
{
public:
	BOOL mCheckFrameNum;
	char mFileName[100];
	int mFrameNum;
	float mLastUsedTime;
	CRITICAL_SECTION mLock;
	TW2AddIn::MOTION2_FOR_GXD mDATA;
	BOOL mCheckValidState;
};


class GSOBJECT
{
public:
	BOOL mCheckValidState;
	char mFileName[100];
	TW2AddIn::SOBJECT2_FOR_GXD mDATA;
	float mLastUsedTime;
	CRITICAL_SECTION mCritical;
  
	GSOBJECT()
	{
		Init();
		InitializeCriticalSection(&this->mCritical);
	}
	void Init()
	{
		this->mCheckValidState = FALSE;
		this->mFileName[0] = 0;
		this->mDATA.mCheckValidState = FALSE;
	}
	void Free()
	{
	    EnterCriticalSection(&this->mCritical);
		this->mCheckValidState = 0;
		this->mDATA.Free();
		LeaveCriticalSection(&this->mCritical);
	}
	
	void DisplaySObject(int tDrawSort, float pFrame, float *tL, float tYAngle, float tHeightForCulling, GMOTION *tMOTION, BOOL tLoadSort)
	{
		//Hook and Call Original function
		//void GSOBJECT::DisplaySObject(GSOBJECT* This, int tDrawSort, float pFrame, float *tL, float tYAngle, float tHeightForCulling, GMOTION *tMOTION, BOOL tLoadSort);
		ori_GSOBJECT_DisplaySObject(this, tDrawSort, pFrame, tL, tYAngle, tHeightForCulling, tMOTION, tLoadSort);
	}
};


//initialize new object
GSOBJECT new_gsobject;

//init mFileName
sprintf( new_gsobject.mFileName, "%s", "G03_GDATA\\D04_GSOBJECT\\010\\A%03d001%03d.SOBJECT", 1, 28 );
4.Use GSOBJECT and Hook AVATAR_OBJECT:: Draw
Code:
class UTIL
{
public:
	static BOOL CheckPossibleDrawMeWithCamera(float tCoord[3], float tLength)
	{
		//Hook and Call Original function
		BOOL res = ori_UTIL_CheckPossibleDrawMeWithCamera(  );
		return res;
		
		//float v3; // [esp+8h] [ebp-Ch]
		//float v4; // [esp+10h] [ebp-4h]
		//v4 = (mGXD[0].mCameraEye.z - tCoord[2]) * (mGXD[0].mCameraEye.z - tCoord[2]) + (mGXD[0].mCameraEye.y - (tLength * 0.5 + tCoord[1])) * (mGXD[0].mCameraEye.y - (tLength * 0.5 + tCoord[1])) + (mGXD[0].mCameraEye.x - *tCoord) * (mGXD[0].mCameraEye.x - *tCoord);
		//v3 = sqrt(v4);
		//return v3 >= 10.0f;
	}
}

class GDATA
{
public:
	static GMOTION* ReturnCharacterMotion(int aPreviousTribe, int aGender, int aType, int aSort, int aLevel1, int aLevel2, int aAnimalNumber)
	{
		//Hook and Call Original function
		GMOTION* res = ori_GDATA_ReturnCharacterMotion(aPreviousTribe, aGender, aType, aSort, aLevel1, aLevel2, aAnimalNumber);
		return res;
	}
};

class AVATAR_OBJECT
{
public:

	BOOL mCheckValidState;
	DWORD mServerIndex;
	DWORD mUniqueNumber;
	float mUpdateTime;
	float mUpdateTimeForRageTime;
	float mUpdateTime3;
	OBJECT_FOR_AVATAR mDATA;	
	BYTE data[1];//other unknow data
	
	//find and hook this function
	static void Draw( AVATAR_OBJECT* This, int tDrawSort, int tObjIndex, float dTime )
	{
		BOOL isLocalClient = tObjIndex == 0;
		GMOTION *tMOTION;
		
		if ( !This->mCheckValidState || tDrawSort < 1 || tDrawSort > 2 || !This->mDATA.aVisibleState || !UTIL::CheckPossibleDrawMeWithCamera(This->mDATA.aAction.aLocation, 20.0f) )
			return;
		
		int tAnimalNumber = 0;
		if ( !This->mDATA.aAnimalAbsorbState )
			tAnimalNumber = This->mDATA.aAnimalNumber;			
		tMOTION = GDATA::ReturnCharacterMotion(This->mDATA.aPreviousTribe, This->mDATA.aGender, This->mDATA.aAction.aType, This->mDATA.aAction.aSort, This->mDATA.aLevel1, This->mDATA.aLevel2, tAnimalNumber);
				
		if( This->mDATA.aCostume == new_costume_id ) {
			new_gsobject.DisplaySObject( tDrawSort, This->mDATA.aAction.aFrame, This->mDATA.aAction.aLocation, This->mDATA.aAction.aFront, 20.0f, tMOTION, isLocalClient );
		}
	}
};
Code:
on exit dll function
void dll_exit()
{
	new_gsobject.Free();
}
Hello,
First of all thank you for your sharing.

Can you please say to us how can we create a new SOBJECT or MOTION file
10/31/2022 12:12 lnwnuyhodd#7
Quote:
Originally Posted by zahter55 View Post
@[Only registered and activated users can see links. Click Here To Register...] can u pls say something about existing other systems. Like bottle system. Why is that slipping rows on every log in? Bottle1 878 price1 30 bottle2 879 price2 30 for example in game but after relogin it shows bottle and price1 is 0 but bottle+price2 and 3 gets new value.
save it to db.

Quote:
Originally Posted by kapgankaan View Post
Hello,
First of all thank you for your sharing.

Can you please say to us how can we create a new SOBJECT or MOTION file
You need to understand the structure of 3D and animation in order to create them. If you don't understand, don't do it.

Code:
#ifndef MYHEADER_H
#define MYHEADER_H

#include <GXD.h>

#include "./CString.h"
#include "./DXHelper.h"

#ifndef MYMACRO_H
#define MYMACRO_H

#define HeapCreate( type, size ) (type)HeapAlloc( GetProcessHeap(), 0, size )
#define HeapFree( ptr ) if( ptr ){ ::HeapFree( GetProcessHeap(), 0, ptr ); ptr = NULL; }
#define LodReleaseFree( ptr ) { \
    if ( ptr ) \
    { \
        for ( int i = 0; i < mLODStepNum; i++ ) \
            SAFE_RELEASE( ptr[i] ); \
        HeapFree( ptr ); \
    } \
}

#define LodHeapFree( ptr ) { \
    if ( ptr ) \
    { \
        for ( int i = 0; i < mLODStepNum; i++ ) { \
            HeapFree( ptr[i] ); \
        } \
        HeapFree( ptr ); \
    } \
}

#define ClassFreeArray( ptr, num ) { \
    if ( ptr ) \
    { \
        for ( int k = 0; k < num; k++ ) \
            ptr[k].Free(); \
        HeapFree( ptr ); \
    } \
}

#endif


typedef void (*LOAD_CALLBACK)(void*);

template<typename T>
void ObjectLoadCallback( void* ptr )
{
    T* v = (T*)ptr;
    if( !v->mCheckValidState )
        v->Free();
}

template<typename HEADER, typename T>
static BOOL ReadValue( HEADER h, T val, int size )
{
    if( h->mReadPos + size > (int)h->tOriginal.size() )
        return FALSE;
    memcpy( val, &h->tOriginal[h->mReadPos], size );
    h->mReadPos += size;
    return TRUE;
}

template<typename HEADER, typename T>
static BOOL ReadValue( HEADER h, T val )
{
    return ReadValue( h, val, sizeof(*val) );
}

typedef struct V3HEADER {
    char IsValid = 0;
    char IsCompress = 0;
    char pad0 = 0;
    char pad1 = 0;
    BOOL IsReady = FALSE;
    HANDLE hFile = NULL;
    std::vector<BYTE> tOriginal;
    std::vector<BYTE> tCompress;
    int mReadPos = 0;
    void* cPtr = NULL;
    LOAD_CALLBACK callback = NULL;

    V3HEADER( char* tFileName, const char* tVersionTex, void* ClassPointer, LOAD_CALLBACK Callback )
    {
        if( ClassPointer && Callback )
        {
            cPtr = ClassPointer;
            callback = Callback;
        }
        
        hFile = CreateFileA( tFileName, 0x80000000, 1u, 0, 3u, 0x80u, 0 );
        if ( hFile == INVALID_HANDLE_VALUE )
            return;
        DWORD dwFileSize = GetFileSize( hFile, NULL );
        if( !dwFileSize )
            return;
        tOriginal.resize( dwFileSize );

        DWORD NumberOfBytesRead;
        if ( !ReadFile( hFile, &tOriginal[0], dwFileSize, &NumberOfBytesRead, 0 ) || NumberOfBytesRead != dwFileSize )
            return;

        size_t versionLen = strlen(tVersionTex);
        if( versionLen > 0 )
        {
            std::vector<BYTE> tBuffer;
            tBuffer.resize( versionLen );
            if( !ReadValue( this, &tBuffer[0], tBuffer.size() ) )
                return;
            tBuffer.push_back( '\0' );//safe last char
            if( strcmp( (const char*)&tBuffer[0], tVersionTex ) != 0 )
                return;
            if( !ReadValue( this, &IsValid, 1 ) )
                return;
            if( !ReadValue( this, &IsCompress, 1 ) )
                return;
            if( !ReadValue( this, &pad0, 1 ) )
                return;
            if( !ReadValue( this, &pad1, 1 ) )
                return;
            if( !IsValid )
                return;        
            if ( IsCompress )
            {
                DWORD tOriginalSize, tCompressSize;
                if ( !ReadValue( this, &tOriginalSize ) )
                    return;
                if ( !ReadValue( this, &tCompressSize ) )
                    return;
                tOriginal.resize( tOriginalSize );
                tCompress.resize( tCompressSize );
                if ( !ReadValue( this, &tCompress[0], tCompressSize ) )
                    return;
                if ( !mGXD.Decompress( tCompressSize, (BYTE*)&tCompress[0], tOriginalSize, (BYTE*)&tOriginal[0] ) )
                    return;
            }
        }
        MYDEBUG();
        mReadPos = 0;
        IsReady = TRUE;
    }
    ~V3HEADER()
    {
        if ( hFile )
        {
            CloseHandle( hFile );
        }
        if( cPtr && callback )
            callback( cPtr );
        tOriginal.clear();
        tCompress.clear();
    }
} V3HEADER;

typedef struct UHEADER
{
    BOOL IsReady = FALSE;
    void* cPtr = NULL;
    LOAD_CALLBACK callback = NULL;
    std::vector<BYTE> tOriginal;
    int mReadPos = 0;

    UHEADER( V3HEADER* h, void* ClassPointer, LOAD_CALLBACK Callback )
    {
        if( ClassPointer && Callback )
        {
            cPtr = ClassPointer;
            callback = Callback;
        }
        //for( int i = 0; i < h->tOriginal.size(); i++ )
        //    tOriginal.push_back( h->tOriginal[i] );
        tOriginal = h->tOriginal;
        mReadPos = h->mReadPos;
        IsReady = TRUE;
    }
    ~UHEADER()
    {
        //tOriginal.clear();
        if( cPtr && callback )
            callback( cPtr );
    }
} UHEADER;


typedef struct THEADER {
    BOOL IsReady = FALSE;
    void* cPtr = NULL;
    LOAD_CALLBACK callback = NULL;
    std::vector<BYTE> tOriginal;
    std::vector<BYTE> tCompress;
    int mReadPos = 0;

    THEADER( UHEADER* h, void* ClassPointer, LOAD_CALLBACK Callback )
    {
        if( ClassPointer && Callback )
        {
            cPtr = ClassPointer;
            callback = Callback;
        }
        DWORD tOriginalSize, tCompressSize;
        if ( !ReadValue( h, &tOriginalSize ) )
            return;
        if ( !ReadValue( h, &tCompressSize ) )
            return;
        tOriginal.resize( tOriginalSize );
        tCompress.resize( tCompressSize );
        if ( !ReadValue( h, &tCompress[0], tCompressSize ) )
            return;
        if ( !mGXD.Decompress( tCompressSize, (BYTE*)&tCompress[0], tOriginalSize, (BYTE*)&tOriginal[0] ) )
            return;
        IsReady = TRUE;
    }
    ~THEADER()
    {
        tOriginal.clear();
        tCompress.clear();
        if( cPtr && callback )
            callback( cPtr );
    }
} THEADER;


typedef struct MHEADER {
    BOOL IsReady = FALSE;
    void* cPtr = NULL;
    LOAD_CALLBACK callback = NULL;
    std::vector<BYTE> tOriginal;
    std::vector<BYTE> tCompress;
    int mReadPos = 0;

    MHEADER( V3HEADER* h, void* ClassPointer, LOAD_CALLBACK Callback )
    {
        if( ClassPointer && Callback )
        {
            cPtr = ClassPointer;
            callback = Callback;
        }
        DWORD tOriginalSize, tCompressSize;
        if ( !ReadValue( h, &tOriginalSize ) )
            return;
        MYDEBUG();
        if ( !ReadValue( h, &tCompressSize ) )
            return;
        MYDEBUG();
        tOriginal.resize( tOriginalSize );
        tCompress.resize( tCompressSize );
        if ( !ReadValue( h, &tCompress[0], tCompressSize ) )
            return;
        MYDEBUG();
        if ( !mGXD.Decompress( tCompressSize, (BYTE*)&tCompress[0], tOriginalSize, (BYTE*)&tOriginal[0] ) )
            return;
        MYDEBUG();
        IsReady = TRUE;
    }
    ~MHEADER()
    {
        tOriginal.clear();
        tCompress.clear();
        if( cPtr && callback )
            callback( cPtr );
    }
} MHEADER;

#endif // !MYHEADER_H

struct MOTION2_MATRIX
{
    D3DXQUATERNION mQuaternion;
    D3DXVECTOR3 mPosition;
};

BOOL MOTION2_FOR_GXD::Load( char *tFileName )
{
    if ( mCheckValidState )
        return 0;
    
    V3HEADER v3( tFileName, "MOTION3", this, (LOAD_CALLBACK)ObjectLoadCallback<MOTION2_FOR_GXD> );
    if( !v3.IsReady )
        return FALSE;

    if( !ReadValue( &v3, &mFrameNum ) || mFrameNum < 1 )
        return FALSE;
    if( !ReadValue( &v3, &mBoneNum ) || mBoneNum < 1 )
        return FALSE;

    mKeyMatrix = (D3DXMATRIX*)HeapAlloc( GetProcessHeap(), 0, (mBoneNum * mFrameNum) * sizeof(D3DXMATRIX) );
    if (!mKeyMatrix)
        return FALSE;

    MOTION2_MATRIX v32;
    for ( int i = 0; i < mBoneNum * mFrameNum; i++ )
    {
        if( !ReadValue( &v3, &v32 ) )
            return FALSE;
        D3DXMatrixRotationQuaternion( &mKeyMatrix[i], &v32.mQuaternion );
        mKeyMatrix[i]._41 = v32.mPosition.x;
        mKeyMatrix[i]._42 = v32.mPosition.y;
        mKeyMatrix[i]._43 = v32.mPosition.z;
    }
    mCheckValidState = v3.mReadPos == v3.tOriginal.size();
    return mCheckValidState;
}

BOOL TEXTURE_FOR_GXD::Load( HANDLE hFile, BOOL tCheckCreateTexture, BOOL tCheckRemoveFileData )
{
    BOOL result = FALSE; // eax

    int v24; // [esp+8h] [ebp-A0h]
    unsigned int v25; // [esp+8h] [ebp-A0h]
    unsigned int v26; // [esp+8h] [ebp-A0h]
    char Src[4]; // [esp+Ch] [ebp-9Ch] BYREF
    int v28[31]; // [esp+10h] [ebp-98h] BYREF

    if ( mCheckValidState )
        return FALSE;

    UHEADER* h = (UHEADER*)hFile;
    if ( !ReadValue( h, &mFileDataSize ) )
        return FALSE;

    if ( !mFileDataSize )
        return TRUE;
    THEADER t( h, this, (LOAD_CALLBACK)ObjectLoadCallback<TEXTURE_FOR_GXD> );
    if( !t.IsReady )
        return FALSE;

    mFileData = (BYTE*)HeapAlloc( GetProcessHeap(), 0, mFileDataSize );
    if ( !mFileData )
        return FALSE;
    if( !ReadValue( &t, mFileData, mFileDataSize ) )
        return FALSE;
    if( !ReadValue( &t, &mProcessModeCase ) )
        return FALSE;
    if( !ReadValue( &t, &mAlphaModeCase ) )
        return FALSE;

    if (D3DXGetImageInfoFromFileInMemory( mFileData, mFileDataSize, &mTextureInfo ) >= 0 )
    {
        if (tCheckCreateTexture)
        {
            switch (mGXD.mTextureOptionValue)
            {
            case 0:
                if (mTextureInfo.Format != D3DFMT_DXT1 && mTextureInfo.Format != D3DFMT_DXT2 && mTextureInfo.Format != D3DFMT_DXT3 && mTextureInfo.Format != D3DFMT_DXT5 || 
                    D3DXCreateTextureFromFileInMemoryEx(mGXD.mGraphicDevice, mFileData, mFileDataSize, mTextureInfo.Width, mTextureInfo.Height, 0, 0, mTextureInfo.Format, D3DPOOL_MANAGED, 1, 1, 0, 0, 0, &mTexture) >= 0)
                    goto LABEL_93;
                return FALSE;
            case 1:
                if (!tCheckRemoveFileData || mTextureInfo.Format != D3DFMT_DXT1 && mTextureInfo.Format != D3DFMT_DXT2 && mTextureInfo.Format != D3DFMT_DXT3 && mTextureInfo.Format != D3DFMT_DXT5)
                    goto LABEL_93;
                memcpy(Src, mFileData, sizeof(Src));
                memcpy(v28, mFileData + 4, sizeof(v28));
                if (v28[0] == 124 && (v28[1] & 2) != 0 && (v28[1] & 4) != 0 && (v28[1] & 0x80000) != 0 && (v28[1] & 0x20000) != 0 && v28[4] >> 2 >= 8 && (v28[6] - 1) >= 2)
                {
                    v24 = v28[4];
                    v28[2] = v28[2] >> 1;
                    if (!v28[2])
                        v28[2] = 1;
                    v28[3] = v28[3] >> 1;
                    if (!v28[3])
                        v28[3] = 1;
                    v28[4] = v28[4] >> 2;
                    --v28[6];
                    memcpy(&mFileData[v24], Src, 4u);
                    memcpy(&mFileData[v24 + 4], v28, 124u);
                    D3DXCreateTextureFromFileInMemoryEx(mGXD.mGraphicDevice, &mFileData[v24], mFileDataSize - v24, v28[3], v28[2], 0, 0, mTextureInfo.Format, D3DPOOL_MANAGED, 1, 1, 0, 0, 0, &mTexture);
                    goto LABEL_93;
                }
                if (D3DXCreateTextureFromFileInMemoryEx(mGXD.mGraphicDevice, mFileData, mFileDataSize, mTextureInfo.Width, mTextureInfo.Height, 0, 0, mTextureInfo.Format, D3DPOOL_MANAGED, 1, 1, 0, 0, 0, &mTexture) >= 0)
                    goto LABEL_93;
                break;
            case 2:
                if (!tCheckRemoveFileData || mTextureInfo.Format != D3DFMT_DXT1 && mTextureInfo.Format != D3DFMT_DXT2 && mTextureInfo.Format != D3DFMT_DXT3 && mTextureInfo.Format != D3DFMT_DXT5)
                    goto LABEL_93;
                memcpy(Src, mFileData, sizeof(Src));
                memcpy(v28, mFileData + 4, sizeof(v28));
                if (v28[0] == 124 && (v28[1] & 2) != 0 && (v28[1] & 4) != 0 && (v28[1] & 0x80000) != 0 && (v28[1] & 0x20000) != 0 && v28[4] >> 4 >= 8 && (v28[6] - 2) >= 2)
                {
                    v25 = v28[4] + (v28[4] >> 2);
                    v28[2] = v28[2] >> 2;
                    if (!v28[2])
                        v28[2] = 1;
                    v28[3] = v28[3] >> 2;
                    if (!v28[3])
                        v28[3] = 1;
                    v28[4] = v28[4] >> 4;
                    v28[6] -= 2;
                    memcpy(&mFileData[v25], Src, 4u);
                    memcpy(&mFileData[v25 + 4], v28, 0x7Cu);
                    D3DXCreateTextureFromFileInMemoryEx(mGXD.mGraphicDevice, &mFileData[v25], mFileDataSize - v25, v28[3], v28[2], 0, 0, mTextureInfo.Format, D3DPOOL_MANAGED, 1, 1, 0, 0, 0, &mTexture);
                }
                else if (D3DXCreateTextureFromFileInMemoryEx(mGXD.mGraphicDevice, mFileData, mFileDataSize, mTextureInfo.Width, mTextureInfo.Height, 0, 0, mTextureInfo.Format, D3DPOOL_MANAGED, 1, 1, 0, 0, 0, &mTexture) < 0)
                {
                    break;
                }
                goto LABEL_93;
            case 3:
                if (!tCheckRemoveFileData || mTextureInfo.Format != D3DFMT_DXT1 && mTextureInfo.Format != D3DFMT_DXT2 && mTextureInfo.Format != D3DFMT_DXT3 && mTextureInfo.Format != D3DFMT_DXT5)
                    goto LABEL_93;
                memcpy(Src, mFileData, sizeof(Src));
                memcpy(v28, mFileData + 4, sizeof(v28));
                if (v28[0] == 124 && (v28[1] & 2) != 0 && (v28[1] & 4) != 0 && (v28[1] & 0x80000) != 0 && (v28[1] & 0x20000) != 0 && v28[4] >> 6 >= 8 && (v28[6] - 3) >= 2)
                {
                    v26 = (v28[4] >> 4) + v28[4] + (v28[4] >> 2);
                    v28[2] = v28[2] >> 3;
                    if (!v28[2])
                        v28[2] = 1;
                    v28[3] = v28[3] >> 3;
                    if (!v28[3])
                        v28[3] = 1;
                    v28[4] = v28[4] >> 6;
                    v28[6] -= 3;
                    memcpy(&mFileData[v26], Src, 4u);
                    memcpy(&mFileData[v26 + 4], v28, 0x7Cu);
                    D3DXCreateTextureFromFileInMemoryEx(mGXD.mGraphicDevice, &mFileData[v26], mFileDataSize - v26, v28[3], v28[2], 0, 0, mTextureInfo.Format, D3DPOOL_MANAGED, 1, 1, 0, 0, 0, &mTexture);
                    goto LABEL_93;
                }
                if (D3DXCreateTextureFromFileInMemoryEx(mGXD.mGraphicDevice, mFileData, mFileDataSize, mTextureInfo.Width, mTextureInfo.Height, 0, 0, mTextureInfo.Format, D3DPOOL_MANAGED, 1, 1, 0, 0, 0, &mTexture) >= 0)
                    goto LABEL_93;
            default:
                break;
            }
        }
        else
        {
        LABEL_93:
            mCheckValidState = TRUE;
            if ( tCheckRemoveFileData )
            {
                HeapFree( mFileData );
            }
            result = TRUE;
        }
    }
    return result;
}

BOOL SKIN2_FOR_GXD::Load( HANDLE hFile )
{
    int i;
    LPVOID v31;
    LPVOID v32;

    if ( mCheckValidState )
        return 0;

    UHEADER h( (V3HEADER*)hFile, this, (LOAD_CALLBACK)ObjectLoadCallback<SKIN2_FOR_GXD> );

    if ( !ReadValue( &h, &mCheckValidState ) )
        return 0;
    if ( !mCheckValidState )
        return 1;
    mCheckValidState = FALSE;
    if ( !ReadValue( &h,&mEffect ) )
        return 0;
    if ( !ReadValue( &h,&mSize ) )
        return 0;
    if ( !ReadValue( &h, mVertexBufferForBillboard, sizeof(mVertexBufferForBillboard) ) )
        return 0;
    if ( !ReadValue( &h,&mLODStepNum ) )
        return 0;
    int lodSize = 4 * mLODStepNum;
    mVertexNum = HeapCreate( int*, lodSize );
    if ( !mVertexNum )
        return 0;
    mVertexBuffer = HeapCreate( IDirect3DVertexBuffer9**, lodSize );
    if ( !mVertexBuffer )
        return 0;
    for ( i = 0; i < mLODStepNum; mVertexBuffer[i++] = 0 )
        ;
    mTrisNum = HeapCreate( int*, lodSize );
    if ( !mTrisNum )
        return 0;
    mIndexBuffer = HeapCreate( IDirect3DIndexBuffer9**, lodSize );
    if ( !mIndexBuffer )
        return 0;
    for ( i = 0; i < mLODStepNum; mIndexBuffer[i++] = 0 )
        ;
    mShadowVertexBuffer = HeapCreate( SKINSHADOWVERTEX2_FOR_GXD**, lodSize );
    if ( !mShadowVertexBuffer )
        return 0;
    for ( i = 0; i < mLODStepNum; mShadowVertexBuffer[i++] = 0 )
        ;
    mShadowIndexBuffer = HeapCreate( WORD**, lodSize );
    if ( !mShadowIndexBuffer )
        return 0;
    for ( i = 0; i < mLODStepNum; mShadowIndexBuffer[i++] = 0 )
        ;
    mShadowEdgeBuffer = HeapCreate( WORD**, lodSize );
    if ( !mShadowEdgeBuffer )
        return 0;
    for ( i = 0; i < mLODStepNum; mShadowEdgeBuffer[i++] = 0 )
        ;
    for ( i = 0; i < mLODStepNum; ++i )
    {
        if ( !ReadValue( &h, &mVertexNum[i] ) )
            return 0;
        int vertexSize = sizeof(SKINVERTEX2_FOR_GXD) * mVertexNum[i];
        if( mGXD.mGraphicDevice->CreateVertexBuffer( vertexSize, D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &mVertexBuffer[i], 0) < 0 || mVertexBuffer[i]->Lock( 0, 0, &v31, 0 ) < 0 )
            return 0;
        if ( !ReadValue( &h, v31, vertexSize ) )
        {
            mVertexBuffer[i]->Unlock();
            return 0;
        }
        if ( mVertexBuffer[i]->Unlock() < 0 )
            return 0;
        if( !ReadValue( &h, &mTrisNum[i] ) )
            return 0;
        int indexSize = 6 * mTrisNum[i];
        if ( mGXD.mGraphicDevice->CreateIndexBuffer( indexSize, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &mIndexBuffer[i], 0 ) < 0 || mIndexBuffer[i]->Lock( 0, 0, &v32, 0) < 0 )
            return 0;
        if ( !ReadValue( &h, v32, indexSize ) )
        {
            mIndexBuffer[i]->Unlock();
            return 0;
        }
        if ( mIndexBuffer[i]->Unlock() < 0 )
            return 0;
        int v24 = sizeof(SKINSHADOWVERTEX2_FOR_GXD) * mVertexNum[i];
        mShadowVertexBuffer[i] = HeapCreate( SKINSHADOWVERTEX2_FOR_GXD*, v24 );
        if ( !mShadowVertexBuffer[i] )
            return 0;
        if ( !ReadValue( &h, mShadowVertexBuffer[i], v24 ) )
            return 0;
        mShadowIndexBuffer[i] = HeapCreate( WORD*, indexSize );
        if ( !mShadowIndexBuffer[i] )
            return 0;
        if ( !ReadValue( &h, mShadowIndexBuffer[i], indexSize ) )
            return 0;
        mShadowEdgeBuffer[i] = HeapCreate( WORD*, indexSize );
        if ( !mShadowEdgeBuffer[i] || !ReadValue( &h, mShadowEdgeBuffer[i], indexSize ) )
            return 0;
    }
    if ( !mDiffuseMap.Load( (HANDLE)&h, 1, 1 ) || !mNormalMap.Load( (HANDLE)&h, 1, 1 ) )
        return 0;
    if ( !mGXD.mNormalMapOptionValue )
        mNormalMap.Free();
    if ( !mSpecularMap.Load( (HANDLE)&h, 1, 1 ) )
        return 0;
    if ( mGXD.mNormalMapOptionValue != 2 )
        mSpecularMap.Free();
    if ( !ReadValue( &h, &mAnimationMapNum ) )
        return 0;
    if ( mAnimationMapNum > 0 )
    {
        mAnimationMap = HeapCreate( TEXTURE_FOR_GXD*, sizeof(TEXTURE_FOR_GXD) * mAnimationMapNum );
        if ( !mAnimationMap )
        {
            return 0;
        }
        for ( i = 0; i < mAnimationMapNum; ++i )
            mAnimationMap[i].Init();
        for ( i = 0; i < mAnimationMapNum; ++i )
        {
            if ( !mAnimationMap[i].Load( (HANDLE)&h, 1, 1) )
                return 0;
        }
    }

    ((V3HEADER*)hFile)->mReadPos = h.mReadPos;

    mCheckValidState = TRUE;

    return 1;
}

BOOL SOBJECT2_FOR_GXD::Load( char* tFileName )
{
    BOOL result = FALSE;
    int i;

    if ( mCheckValidState )
        return 0;

    V3HEADER v3( tFileName, "SOBJECT3", this, (LOAD_CALLBACK)ObjectLoadCallback<SKIN2_FOR_GXD> );
    if( !v3.IsReady )
        return FALSE;

    if( !ReadValue( &v3, &mSkinNum ) || mSkinNum < 1 )
        return FALSE;

    mSkin = (SKIN2_FOR_GXD*)HeapAlloc( GetProcessHeap(), 0, sizeof(*mSkin) * mSkinNum );
    if ( !mSkin )
        return FALSE;
    
    for ( i = 0; i < mSkinNum; i++ )
        mSkin[i].Init();
    for ( i = 0; i < mSkinNum; i++ )
    {
        mSkin[i].Init();
        if ( !mSkin[i].Load( (HANDLE)&v3 ) )
            return FALSE;
    }

    mCheckValidState = v3.mReadPos == v3.tOriginal.size();

    return mCheckValidState;
}
10/31/2022 13:10 zahter55#8
Quote:
Originally Posted by lnwnuyhodd View Post
save it to db.
Already saving. I have written its ints to my sql, to db.cpps, when i use a bottle price goes down it saves but as i say i use 3rd bottle but after relogin as i see i have been used 2nd bottle. [Only registered and activated users can see links. Click Here To Register...]
10/31/2022 13:32 lnwnuyhodd#9
Quote:
Originally Posted by zahter55 View Post
Already saving. I have written its ints to my sql, to db.cpps, when i use a bottle price goes down it saves but as i say i use 3rd bottle but after relogin as i see i have been used 2nd bottle. [Only registered and activated users can see links. Click Here To Register...]
Code:
void __thiscall DRUNKUI::Draw(DRUNKUI *self, int mX, int mY)
{
    int v3; // esi
    int v4; // esi
    int v5; // eax
    int v6; // eax
    int v7; // eax
    int v8; // eax
    int v9; // eax
    int v10; // eax
    int v11; // esi
    int v12; // [esp-Ch] [ebp-414h]
    int v13; // [esp-Ch] [ebp-414h]
    int v14; // [esp-4h] [ebp-40Ch]
    int v15; // [esp-4h] [ebp-40Ch]
    int v16; // [esp-4h] [ebp-40Ch]
    int v17; // [esp-4h] [ebp-40Ch]
    ITEM_INFO *v19; // [esp+8h] [ebp-400h]
    int sX; // [esp+Ch] [ebp-3FCh]
    int sXa; // [esp+Ch] [ebp-3FCh]
    char tString[1000]; // [esp+10h] [ebp-3F8h] BYREF
    int i; // [esp+3FCh] [ebp-Ch]
    int sY; // [esp+400h] [ebp-8h]
    int v25; // [esp+404h] [ebp-4h]

    if ( self->mActive )
    {
        i = 0;
        sY = 0;
        v25 = 0;
        tString[0] = 0;
        memset(&tString[1], 0, 999u);
        v3 = mMYINFO[0].mScreenXSize / 2;
        self->uX = v3 - GIMAGE2D::GetXSize(&mGDATA[0].mUI_MAIN[3945]) / 2;
        v4 = mMYINFO[0].mScreenYSize / 2;
        self->uY = v4 - GIMAGE2D::GetYSize(&mGDATA[0].mUI_MAIN[3945]) / 2;
        if ( GIMAGE2D::CheckIn(&mGDATA[0].mUI_MAIN[3945], self->uX, self->uY, mX, mY) )
            POINTER::Set(0);
        GIMAGE2D::Display(&mGDATA[0].mUI_MAIN[3945], self->uX, self->uY);
        for ( i = 0; i < 10; ++i )
        {
            if ( mMYINFO[0].mUseAvatar.aBottle[i] >= 1 )
            {
                sX = self->uX + 55 * (i % 5) + 19;
                sY = self->uY + 55 * (i / 5) + 41;
                v19 = ITEM::Search(mMYINFO[0].mUseAvatar.aBottle[i]);
                if ( v19 )
                {
                    v25 = v19->iDataNumber2D - 1;
                    GIMAGE2D::Display(&mGDATA[0].mUI_ITEM[v25], sX, sY);
                    if ( mMYINFO[0].mUseAvatar.aBottleIndex == i && mMYINFO[0].mUseAvatar.aBottleTime > 0 )
                        GIMAGE2D::Display(&mGDATA[0].mUI_MAIN[2792], sX, sY);
                    if ( mMYINFO[0].mBottleIndex == i )
                        GIMAGE2D::Display(&mGDATA[0].mUI_MAIN[2627], sX, sY);
                }
            }
        }
        if ( self->bIsClick[0] )
        {
            v15 = self->uY + DRUNKUI::GetPosY(3947);
            v7 = DRUNKUI::GetPosX(3947);
            GIMAGE2D::Display(&mGDATA[0].mUI_MAIN[3947], self->uX + v7, v15);
        }
        else
        {
            v12 = self->uY + DRUNKUI::GetPosY(3946);
            v5 = DRUNKUI::GetPosX(3946);
            if ( GIMAGE2D::CheckIn(&mGDATA[0].mUI_MAIN[3946], self->uX + v5, v12, mX, mY) )
            {
                v14 = self->uY + DRUNKUI::GetPosY(3946);
                v6 = DRUNKUI::GetPosX(3946);
                GIMAGE2D::Display(&mGDATA[0].mUI_MAIN[3946], self->uX + v6, v14);
            }
        }
        if ( self->bIsClick[2] )
        {
            v17 = self->uY + DRUNKUI::GetPosY(3951);
            v10 = DRUNKUI::GetPosX(3951);
            GIMAGE2D::Display(&mGDATA[0].mUI_MAIN[3951], self->uX + v10, v17);
        }
        else
        {
            v13 = self->uY + DRUNKUI::GetPosY(3950);
            v8 = DRUNKUI::GetPosX(3950);
            if ( GIMAGE2D::CheckIn(&mGDATA[0].mUI_MAIN[3950], self->uX + v8, v13, mX, mY) )
            {
                v16 = self->uY + DRUNKUI::GetPosY(3950);
                v9 = DRUNKUI::GetPosX(3950);
                GIMAGE2D::Display(&mGDATA[0].mUI_MAIN[3950], self->uX + v9, v16);
            }
        }
        for ( i = 0; i < 10; ++i )
        {
            if ( mMYINFO[0].mUseAvatar.aBottle[i] )
            {
                sprintf(tString, "%d / %d", mMYINFO[0].mUseAvatar.aBottleCount[i], 30);
                v11 = self->uX + 55 * (i % 5) + 44;
                sXa = v11 - UTIL::ReturnStringLength(tString) / 2;
                sY = self->uY + 55 * (i / 5) + 77;
                UTIL::DrawFont2D(tString, sXa, sY, 1);
            }
        }
    }
}
It's either wrong with your structure or you're doing it wrong, that's all.
10/31/2022 14:19 zahter55#10
.