Jump to content

Reversed Moving UI Classes


Recommended Posts

  • Honorable Member

Hi fellas,

Here are the official version of these classes:

  1. CMoveTextLine - Used in Yutnori
  2. CMoveImageBox - Used in MonsterCard, Rumi and CatchKing
  3. CMoveScaleImageBox - Used in Yutnori

I already reversed them months ago except the CMoveScaleImageBox but yesterday I finished them coz they had a little problem, but now seems working well.
What you must know, this release isn't stable, I just reversed them, and tested with the scripts what you will see, so I couldn't stress them, they may have problems. And I don't recommend to use the SetScalePivotCenter function, I don't know why but works a bit strange than the official, it needs something more during the texture load in.

Video of them:

Spoiler

 

 

Spoiler

1.) Open EterPythonLib\PythonWindow.h and add the following class-definitions anywhere in the UI namespace:


	class CMoveTextLine : public CTextLine
	{
	public:
		CMoveTextLine(PyObject * ppyObject);
		virtual ~CMoveTextLine();

	public:
		static DWORD Type();

		void SetMoveSpeed(float fSpeed);
		void SetMovePosition(float fDstX, float fDstY);
		bool GetMove();
		void MoveStart();
		void MoveStop();

	protected:
		void OnUpdate();
		void OnRender();
		void OnEndMove();
		void OnChangePosition();

		BOOL OnIsType(DWORD dwType);

		D3DXVECTOR2 m_v2SrcPos, m_v2DstPos, m_v2NextPos, m_v2Direction, m_v2NextDistance;
		float m_fDistance, m_fMoveSpeed;
		bool m_bIsMove;
	};
	class CMoveImageBox : public CImageBox
	{
		public:
			CMoveImageBox(PyObject * ppyObject);
			virtual ~CMoveImageBox();

			static DWORD Type();

			void SetMoveSpeed(float fSpeed);
			void SetMovePosition(float fDstX, float fDstY);
			bool GetMove();
			void MoveStart();
			void MoveStop();

		protected:
			virtual void OnCreateInstance();
			virtual void OnDestroyInstance();

			virtual void OnUpdate();
			virtual void OnRender();
			virtual void OnEndMove();

			BOOL OnIsType(DWORD dwType);

			D3DXVECTOR2 m_v2SrcPos, m_v2DstPos, m_v2NextPos, m_v2Direction, m_v2NextDistance;
			float m_fDistance, m_fMoveSpeed;
			bool m_bIsMove;
	};
	class CMoveScaleImageBox : public CMoveImageBox
	{
		public:
			CMoveScaleImageBox(PyObject * ppyObject);
			virtual ~CMoveScaleImageBox();

			static DWORD Type();

			void SetMaxScale(float fMaxScale);
			void SetMaxScaleRate(float fMaxScaleRate);
			void SetScalePivotCenter(bool bScalePivotCenter);

		protected:
			virtual void OnCreateInstance();
			virtual void OnDestroyInstance();

			virtual void OnUpdate();

			BOOL OnIsType(DWORD dwType);

			float m_fMaxScale, m_fMaxScaleRate, m_fScaleDistance, m_fAdditionalScale;
			D3DXVECTOR2 m_v2CurScale;
	};

2.) Open EterPythonLib\PythonWindow.cpp and paste the functions of the new classes anywhere you want:


	/// CMoveTextLine
	CMoveTextLine::CMoveTextLine(PyObject * ppyObject) :
		CTextLine(ppyObject),
		m_v2SrcPos(0.0f, 0.0f),
		m_v2DstPos(0.0f, 0.0f),
		m_v2NextPos(0.0f, 0.0f),
		m_v2Direction(0.0f, 0.0f),
		m_v2NextDistance(0.0f, 0.0f),
		m_fDistance(0.0f),
		m_fMoveSpeed(10.0f),
		m_bIsMove(false)
	{
	}

	CMoveTextLine::~CMoveTextLine()
	{
		m_TextInstance.Destroy();
	}

	DWORD CMoveTextLine::Type()
	{
		static DWORD s_dwType = GetCRC32("CMoveTextLine", strlen("CMoveTextLine"));
		return (s_dwType);
	}

	BOOL CMoveTextLine::OnIsType(DWORD dwType)
	{
		if (CMoveTextLine::Type() == dwType)
			return TRUE;

		return FALSE;
	}

	void CMoveTextLine::SetMoveSpeed(float fSpeed)
	{
		m_fMoveSpeed = fSpeed;
	}

	bool CMoveTextLine::GetMove()
	{
		return m_bIsMove;
	}

	void CMoveTextLine::MoveStart()
	{
		m_bIsMove = true;
		m_v2NextPos = m_v2SrcPos;
	}

	void CMoveTextLine::MoveStop()
	{
		m_bIsMove = false;
	}

	void CMoveTextLine::OnEndMove()
	{
		PyCallClassMemberFunc(m_poHandler, "OnEndMove", BuildEmptyTuple());
	}

	void CMoveTextLine::OnChangePosition()
	{
		m_TextInstance.SetPosition((GetDefaultCodePage() == CP_1256) ? m_rect.right : m_rect.left, m_rect.top);
	}

	void CMoveTextLine::SetMovePosition(float fDstX, float fDstY)
	{
		if (fDstX != m_v2DstPos.x || fDstY != m_v2DstPos.y || m_rect.left != m_v2SrcPos.x || m_rect.top != m_v2SrcPos.y)
		{
			m_v2SrcPos.x = m_rect.left;
			m_v2SrcPos.y = m_rect.top;

			m_v2DstPos.x = fDstX;
			m_v2DstPos.y = fDstY;

			D3DXVec2Subtract(&m_v2Direction, &m_v2DstPos, &m_v2SrcPos);

			m_fDistance = (m_v2Direction.y*m_v2Direction.y + m_v2Direction.x*m_v2Direction.x);
			D3DXVec2Normalize(&m_v2Direction, &m_v2Direction);

			if (m_v2SrcPos != m_v2NextPos)
			{
				float fDist = sqrtf(m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);
				m_v2NextPos = m_v2Direction * fDist;
				m_TextInstance.SetPosition(m_v2NextPos.x, m_v2NextPos.y);
			}
		}
	}

	void CMoveTextLine::OnUpdate()
	{
		if (IsShow() && GetMove())
		{
			D3DXVec2Add(&m_v2NextPos, &m_v2NextPos, &(m_v2Direction * m_fMoveSpeed));
			D3DXVec2Subtract(&m_v2NextDistance, &m_v2NextPos, &m_v2SrcPos);

			float fNextDistance = m_v2NextDistance.y * m_v2NextDistance.y + m_v2NextDistance.x * m_v2NextDistance.x;
			if (fNextDistance >= m_fDistance)
			{
				m_v2NextPos = m_v2DstPos;
				MoveStop();
				OnEndMove();
			}

			m_TextInstance.SetPosition(m_v2NextPos.x, m_v2NextPos.y);
			m_TextInstance.Update();
		}
	}

	void CMoveTextLine::OnRender()
	{
		if (IsShow())
			m_TextInstance.Render();
	}

	/// CMoveImageBox
	CMoveImageBox::CMoveImageBox(PyObject * ppyObject) :
		CImageBox(ppyObject),
		m_v2SrcPos(0.0f, 0.0f),
		m_v2DstPos(0.0f, 0.0f),
		m_v2NextPos(0.0f, 0.0f),
		m_v2Direction(0.0f, 0.0f),
		m_v2NextDistance(0.0f, 0.0f),
		m_fDistance(0.0f),
		m_fMoveSpeed(10.0f),
		m_bIsMove(false)
	{
	}

	CMoveImageBox::~CMoveImageBox()
	{
		OnDestroyInstance();
	}

	void CMoveImageBox::OnCreateInstance()
	{
		OnDestroyInstance();

		m_pImageInstance = CGraphicImageInstance::New();
	}

	void CMoveImageBox::OnDestroyInstance()
	{
		if (m_pImageInstance)
		{
			CGraphicImageInstance::Delete(m_pImageInstance);
			m_pImageInstance = NULL;
		}
	}

	DWORD CMoveImageBox::Type()
	{
		static DWORD s_dwType = GetCRC32("CMoveImageBox", strlen("CMoveImageBox"));
		return (s_dwType);
	}

	BOOL CMoveImageBox::OnIsType(DWORD dwType)
	{
		if (CMoveImageBox::Type() == dwType)
			return TRUE;

		return FALSE;
	}

	void CMoveImageBox::OnEndMove()
	{
		PyCallClassMemberFunc(m_poHandler, "OnEndMove", BuildEmptyTuple());
	}

	void CMoveImageBox::SetMovePosition(float fDstX, float fDstY)
	{
		if (fDstX != m_v2DstPos.x || fDstY != m_v2DstPos.y || m_rect.left != m_v2SrcPos.x || m_rect.top != m_v2SrcPos.y)
		{
			m_v2SrcPos.x = m_rect.left;
			m_v2SrcPos.y = m_rect.top;

			m_v2DstPos.x = fDstX;
			m_v2DstPos.y = fDstY;

			D3DXVec2Subtract(&m_v2Direction, &m_v2DstPos, &m_v2SrcPos);

			m_fDistance = (m_v2Direction.x*m_v2Direction.x + m_v2Direction.y*m_v2Direction.y);

			D3DXVec2Normalize(&m_v2Direction, &m_v2Direction);

			if (m_pImageInstance && m_v2SrcPos != m_v2NextPos)
			{
				float fDist = sqrtf(m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);

				m_v2NextPos = m_v2Direction * fDist;
				m_pImageInstance->SetPosition(m_v2NextPos.x, m_v2NextPos.y);
			}
		}
	}

	void CMoveImageBox::SetMoveSpeed(float fSpeed)
	{
		m_fMoveSpeed = fSpeed;
	}

	void CMoveImageBox::MoveStart()
	{
		m_bIsMove = true;
		m_v2NextPos = m_v2SrcPos;
	}

	void CMoveImageBox::MoveStop()
	{
		m_bIsMove = false;
	}

	bool CMoveImageBox::GetMove()
	{
		return m_bIsMove;
	}

	void CMoveImageBox::OnUpdate()
	{
		if (!m_pImageInstance)
			return;

		if (IsShow() && GetMove())
		{
			D3DXVec2Add(&m_v2NextPos, &m_v2NextPos, &(m_v2Direction * m_fMoveSpeed));
			D3DXVec2Subtract(&m_v2NextDistance, &m_v2NextPos, &m_v2SrcPos);

			float fNextDistance = (m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);
			if (fNextDistance >= m_fDistance)
			{
				m_v2NextPos = m_v2DstPos;
				MoveStop();
				OnEndMove();
			}

			m_pImageInstance->SetPosition(m_v2NextPos.x, m_v2NextPos.y);
		}
	}

	void CMoveImageBox::OnRender()
	{
		if (!m_pImageInstance)
			return;

		if (IsShow())
			m_pImageInstance->Render();
	}

	/// CMoveScaleImageBox
	CMoveScaleImageBox::CMoveScaleImageBox(PyObject * ppyObject) :
		CMoveImageBox(ppyObject),
		m_fMaxScale(1.0f),
		m_fMaxScaleRate(1.0f),
		m_fScaleDistance(0.0f),
		m_fAdditionalScale(0.0f),
		m_v2CurScale(1.0f, 1.0f)
	{
	}

	CMoveScaleImageBox::~CMoveScaleImageBox()
	{
		OnDestroyInstance();
	}

	void CMoveScaleImageBox::OnCreateInstance()
	{
		OnDestroyInstance();

		m_pImageInstance = CGraphicImageInstance::New();
	}

	void CMoveScaleImageBox::OnDestroyInstance()
	{
		if (m_pImageInstance)
		{
			CGraphicImageInstance::Delete(m_pImageInstance);
			m_pImageInstance = NULL;
		}
	}

	DWORD CMoveScaleImageBox::Type()
	{
		static DWORD s_dwType = GetCRC32("CMoveScaleImageBox", strlen("CMoveScaleImageBox"));
		return (s_dwType);
	}

	BOOL CMoveScaleImageBox::OnIsType(DWORD dwType)
	{
		if (CMoveScaleImageBox::Type() == dwType)
			return TRUE;

		return FALSE;
	}

	void CMoveScaleImageBox::SetMaxScale(float fMaxScale)
	{
		m_fMaxScale = fMaxScale;
	}

	void CMoveScaleImageBox::SetMaxScaleRate(float fMaxScaleRate)
	{
		m_fMaxScaleRate = fMaxScaleRate;
		float fDistanceRate = m_fDistance * fMaxScaleRate;
		m_fScaleDistance = fDistanceRate;
		m_v2CurScale = m_pImageInstance->GetScale();
		float fDiffScale = m_fMaxScale - m_v2CurScale.x;
		m_fAdditionalScale = fDiffScale / (sqrtf(fDistanceRate) / m_fMoveSpeed);
	}

	void CMoveScaleImageBox::SetScalePivotCenter(bool bScalePivotCenter)
	{
		if (m_pImageInstance)
			m_pImageInstance->SetScalePivotCenter(bScalePivotCenter);
	}

	void CMoveScaleImageBox::OnUpdate()
	{
		if (!m_pImageInstance)
			return;

		if (IsShow() && GetMove())
		{
			D3DXVec2Add(&m_v2NextPos, &m_v2NextPos, &(m_v2Direction * m_fMoveSpeed));
			D3DXVec2Subtract(&m_v2NextDistance, &m_v2NextPos, &m_v2SrcPos);

			float fNextDistance = (m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);
			if (m_fScaleDistance < fNextDistance)
				m_fAdditionalScale *= -1.0f;
			
			D3DXVECTOR2 v2NewScale;
			D3DXVec2Add(&v2NewScale, &m_pImageInstance->GetScale(), &D3DXVECTOR2(m_fAdditionalScale, m_fAdditionalScale));
			if (m_fMaxScale < v2NewScale.x)
				v2NewScale = D3DXVECTOR2(m_fMaxScale, m_fMaxScale);

			if (m_v2CurScale.x > v2NewScale.x)
				v2NewScale = m_v2CurScale;

			m_pImageInstance->SetScale(v2NewScale);

			if (fNextDistance >= m_fDistance)
			{
				m_pImageInstance->SetScale(m_v2CurScale);
				m_v2NextPos = m_v2DstPos;
				MoveStop();
				OnEndMove();
			}

			m_pImageInstance->SetPosition(m_v2NextPos.x, m_v2NextPos.y);
		}
	}

3.1.) Open EterPythonLib\PythonWindowManager.h and extend the enum of the windows with these:


				WT_MOVE_TEXTLINE,
				WT_MOVE_IMAGEBOX,
				WT_MOVE_SCALEIMAGEBOX,

3.2.) Add the following definitions of functions:


			CWindow *	RegisterMoveTextLine(PyObject * po, const char * c_szLayer);
			CWindow *	RegisterMoveImageBox(PyObject * po, const char * c_szLayer);
			CWindow *	RegisterMoveScaleImageBox(PyObject * po, const char * c_szLayer);

4.1.) Open EterPythonLib\PythonWindowManager.cpp and extend the switch statement in the CWindowManager::__NewWindow with these:


			case WT_MOVE_TEXTLINE:
				return new CMoveTextLine(po);
				break;
			case WT_MOVE_IMAGEBOX:
				return new CMoveImageBox(po);
				break;
			case WT_MOVE_SCALEIMAGEBOX:
				return new CMoveScaleImageBox(po);
				break;

4.2.) Add the following functions:


	CWindow * CWindowManager::RegisterMoveTextLine(PyObject * po, const char * c_szLayer)
	{
		assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer));

		CWindow * pWin = new CMoveTextLine(po);
		m_LayerWindowMap[c_szLayer]->AddChild(pWin);

#ifdef __WINDOW_LEAK_CHECK__
		gs_kSet_pkWnd.insert(pWin);
#endif
		return pWin;
	}

	CWindow * CWindowManager::RegisterMoveImageBox(PyObject * po, const char * c_szLayer)
	{
		assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer));

		CWindow * pWin = new CMoveImageBox(po);
		m_LayerWindowMap[c_szLayer]->AddChild(pWin);

#ifdef __WINDOW_LEAK_CHECK__
		gs_kSet_pkWnd.insert(pWin);
#endif
		return pWin;
	}

	CWindow * CWindowManager::RegisterMoveScaleImageBox(PyObject * po, const char * c_szLayer)
	{
		assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer));

		CWindow * pWin = new CMoveScaleImageBox(po);
		m_LayerWindowMap[c_szLayer]->AddChild(pWin);

#ifdef __WINDOW_LEAK_CHECK__
		gs_kSet_pkWnd.insert(pWin);
#endif
		return pWin;
	}

5.1.) Open ETerPythonLib\PythonWindowManagerModule.cpp and add the following functions anywhere you want:


// MoveTextLine
PyObject * wndMgrRegisterMoveTextLine(PyObject * poSelf, PyObject * poArgs)
{
	PyObject * po;
	if (!PyTuple_GetObject(poArgs, 0, &po))
		return Py_BuildException();
	char * szLayer;
	if (!PyTuple_GetString(poArgs, 1, &szLayer))
		return Py_BuildException();

	UI::CWindow * pWindow = UI::CWindowManager::Instance().RegisterMoveTextLine(po, szLayer);
	return Py_BuildValue("i", pWindow);
}

// MoveImageBox
PyObject * wndMgrRegisterMoveImageBox(PyObject * poSelf, PyObject * poArgs)
{
	PyObject * po;
	if (!PyTuple_GetObject(poArgs, 0, &po))
		return Py_BuildException();
	char * szLayer;
	if (!PyTuple_GetString(poArgs, 1, &szLayer))
		return Py_BuildException();

	UI::CWindow * pWindow = UI::CWindowManager::Instance().RegisterMoveImageBox(po, szLayer);
	return Py_BuildValue("i", pWindow);
}

// MoveScaleImageBox
PyObject * wndMgrRegisterMoveScaleImageBox(PyObject * poSelf, PyObject * poArgs)
{
	PyObject * po;
	if (!PyTuple_GetObject(poArgs, 0, &po))
		return Py_BuildException();
	char * szLayer;
	if (!PyTuple_GetString(poArgs, 1, &szLayer))
		return Py_BuildException();

	UI::CWindow * pWindow = UI::CWindowManager::Instance().RegisterMoveScaleImageBox(po, szLayer);
	return Py_BuildValue("i", pWindow);
}

PyObject * wndSetMoveSpeed(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	float fSpeed;
	if (!PyTuple_GetFloat(poArgs, 1, &fSpeed))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveImageBox::Type()) || pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		((UI::CMoveImageBox*)pWindow)->SetMoveSpeed(fSpeed);
	else if (pWindow->IsType(UI::CMoveTextLine::Type()))
		((UI::CMoveTextLine*)pWindow)->SetMoveSpeed(fSpeed);

	return Py_BuildNone();
}

PyObject * wndSetMovePosition(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	float fDstX(0.0f), fDstY(0.0f);
	if (!PyTuple_GetFloat(poArgs, 1, &fDstX))
		return Py_BuildException();
	if (!PyTuple_GetFloat(poArgs, 2, &fDstY))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveImageBox::Type()) || pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		((UI::CMoveImageBox*)pWindow)->SetMovePosition(fDstX, fDstY);
	else if (pWindow->IsType(UI::CMoveTextLine::Type()))
		((UI::CMoveTextLine*)pWindow)->SetMovePosition(fDstX, fDstY);

	return Py_BuildNone();
}

PyObject * wndMoveStart(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveImageBox::Type()) || pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		((UI::CMoveImageBox*)pWindow)->MoveStart();
	else if (pWindow->IsType(UI::CMoveTextLine::Type()))
		((UI::CMoveTextLine*)pWindow)->MoveStart();

	return Py_BuildNone();
}

PyObject * wndMoveStop(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveImageBox::Type()) || pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		((UI::CMoveImageBox*)pWindow)->MoveStop();
	else if (pWindow->IsType(UI::CMoveTextLine::Type()))
		((UI::CMoveTextLine*)pWindow)->MoveStop();

	return Py_BuildNone();
}

PyObject * wndGetMove(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveImageBox::Type()) || pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		return Py_BuildValue("i", ((UI::CMoveImageBox*)pWindow)->GetMove());
	else if (pWindow->IsType(UI::CMoveTextLine::Type()))
		return Py_BuildValue("i", ((UI::CMoveTextLine*)pWindow)->GetMove());
	else
		return Py_BuildValue("i", 0);
}

PyObject * wndSetMaxScale(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	float fMaxScale = 1.0f;
	if (!PyTuple_GetFloat(poArgs, 1, &fMaxScale))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		((UI::CMoveScaleImageBox*)pWindow)->SetMaxScale(fMaxScale);

	return Py_BuildNone();
}

PyObject * wndSetMaxScaleRate(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	float fMaxScaleRate = 1.0f;
	if (!PyTuple_GetFloat(poArgs, 1, &fMaxScaleRate))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		((UI::CMoveScaleImageBox*)pWindow)->SetMaxScaleRate(fMaxScaleRate);

	return Py_BuildNone();
}

PyObject * wndSetScalePivotCenter(PyObject * poSelf, PyObject * poArgs)
{
	UI::CWindow * pWindow;
	if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
		return Py_BuildException();

	bool bScalePivotCenter = false;
	if (!PyTuple_GetBoolean(poArgs, 1, &bScalePivotCenter))
		return Py_BuildException();

	if (pWindow->IsType(UI::CMoveScaleImageBox::Type()))
		((UI::CMoveScaleImageBox*)pWindow)->SetScalePivotCenter(bScalePivotCenter);

	return Py_BuildNone();
}

5.2.) Enable them in the methodlist:


		{ "RegisterMoveTextLine",		wndMgrRegisterMoveTextLine,			METH_VARARGS },
		{ "RegisterMoveImageBox",		wndMgrRegisterMoveImageBox,			METH_VARARGS },
		{ "RegisterMoveScaleImageBox",	wndMgrRegisterMoveScaleImageBox,	METH_VARARGS },

		{ "SetMoveSpeed",				wndSetMoveSpeed,					METH_VARARGS },
		{ "SetMovePosition",			wndSetMovePosition,					METH_VARARGS },
		{ "MoveStart",					wndMoveStart,						METH_VARARGS },
		{ "MoveStop",					wndMoveStop,						METH_VARARGS },
		{ "GetMove",					wndGetMove,							METH_VARARGS },

		{ "SetMaxScale",				wndSetMaxScale,						METH_VARARGS },
		{ "SetMaxScaleRate",			wndSetMaxScaleRate,					METH_VARARGS },
		{ "SetScalePivotCenter",		wndSetScalePivotCenter,				METH_VARARGS },

6.1.) Open EterLib\GrpImageInstance.h and add the following definitions of functions in the CGraphicImageInstance class as public:


		void SetScale(float fx, float fy);
		void SetScale(D3DXVECTOR2 v2Scale);
		const D3DXVECTOR2 & GetScale() const;
		void SetScalePercent(BYTE byPercent);
		void SetScalePivotCenter(bool bScalePivotCenter);

6.2.) Add the following new variables into the CGraphinImageInstance class as protected:


		D3DXVECTOR2 m_v2Scale;
		bool m_bScalePivotCenter;

7.1.) Open EterLib\GrpImageInstance.cpp and initialize the new variables with default values in the Initialize function:


	m_v2Scale.x = m_v2Scale.y = 1.0f;
	m_bScalePivotCenter = false;

7.2.) Add the new functions anywhere you want:


void CGraphicImageInstance::SetScale(float fx, float fy)
{
	m_v2Scale.x = fx;
	m_v2Scale.y = fy;
}

void CGraphicImageInstance::SetScale(D3DXVECTOR2 v2Scale)
{
	m_v2Scale = v2Scale;
}

void CGraphicImageInstance::SetScalePercent(BYTE byPercent)
{
	m_v2Scale.x *= byPercent;
	m_v2Scale.y *= byPercent;
}

const D3DXVECTOR2 & CGraphicImageInstance::GetScale() const
{
	return m_v2Scale;
}

void CGraphicImageInstance::SetScalePivotCenter(bool bScalePivotCenter)
{
	m_bScalePivotCenter = bScalePivotCenter;
}

7.3.) Replace the following in the OnRender and OnRenderCoolTime:


	float fimgWidth = pImage->GetWidth();
	float fimgHeight = pImage->GetHeight();

With this:


	float fimgWidth = pImage->GetWidth() * m_v2Scale.x;
	float fimgHeight = pImage->GetHeight() * m_v2Scale.y;

7.4.) Add the following into the OnRender function, below of the filling up the vertices(so before the CGraphicBase::SetPDTStream):


	if (m_bScalePivotCenter)
	{
		vertices[0].texCoord = TTextureCoordinate(eu, sv);
		vertices[1].texCoord = TTextureCoordinate(su, sv);
		vertices[2].texCoord = TTextureCoordinate(eu, ev);
		vertices[3].texCoord = TTextureCoordinate(su, ev);
	}

8.1.) Open root\ui.py and add the following classes:


class MoveTextLine(TextLine):
	def __init__(self):
		TextLine.__init__(self)
		self.end_move_event_func = None
		self.end_move_event_args = None

	def __del__(self):
		TextLine.__del__(self)
		self.end_move_event_func = None
		self.end_move_event_args = None

	def RegisterWindow(self, layer):
		self.hWnd = wndMgr.RegisterMoveTextLine(self, layer)

	def SetMovePosition(self, dst_x, dst_y):
		wndMgr.SetMovePosition(self.hWnd, dst_x, dst_y)

	def SetMoveSpeed(self, speed):
		wndMgr.SetMoveSpeed(self.hWnd, speed)

	def MoveStart(self):
		wndMgr.MoveStart(self.hWnd)
	def MoveStop(self):
		wndMgr.MoveStop(self.hWnd)
	def GetMove(self):
		return wndMgr.GetMove(self.hWnd)

	def OnEndMove(self):
		if self.end_move_event_func:
			apply(self.end_move_event_func, self.end_move_event_args)

	def SetEndMoveEvent(self, event, *args):
		self.end_move_event_func = event
		self.end_move_event_args = args

class MoveImageBox(ImageBox):
	def __init__(self, layer = "UI"):
		ImageBox.__init__(self, layer)
		self.end_move_event = None

	def __del__(self):
		ImageBox.__del__(self)
		self.end_move_event = None

	def RegisterWindow(self, layer):
		self.hWnd = wndMgr.RegisterMoveImageBox(self, layer)

	def MoveStart(self):
		wndMgr.MoveStart(self.hWnd)
	def MoveStop(self):
		wndMgr.MoveStop(self.hWnd)
	def GetMove(self):
		return wndMgr.GetMove(self.hWnd)

	def SetMovePosition(self, dst_x, dst_y):
		wndMgr.SetMovePosition(self.hWnd, dst_x, dst_y)

	def SetMoveSpeed(self, speed):
		wndMgr.SetMoveSpeed(self.hWnd, speed)

	def OnEndMove(self):
		if self.end_move_event:
			self.end_move_event()

	def SetEndMoveEvent(self, event):
		self.end_move_event = event

class MoveScaleImageBox(MoveImageBox):
	def __init__(self, layer = "UI"):
		MoveImageBox.__init__(self, layer)

	def __del__(self):
		MoveImageBox.__del__(self)

	def RegisterWindow(self, layer):
		self.hWnd = wndMgr.RegisterMoveScaleImageBox(self, layer)

	def SetMaxScale(self, scale):
		wndMgr.SetMaxScale(self.hWnd, scale)

	def SetMaxScaleRate(self, pivot):
		wndMgr.SetMaxScaleRate(self.hWnd, pivot)

	def SetScalePivotCenter(self, flag):
		wndMgr.SetScalePivotCenter(self.hWnd, flag)

9.) TestScript.py:


class MoveTextLineTest(ui.BoardWithTitleBar):
	def __init__(self):
		ui.BoardWithTitleBar.__init__(self)

		self.__LoadWindow()
		self.__LoadGUI()

	def __del__(self):
		ui.BoardWithTitleBar.__del__(self)

	def __LoadWindow(self):
		self.SetSize(200, 100)
		self.SetPosition(0, 0)
		self.AddFlag('movable')
		self.AddFlag('float')
		self.SetTitleName("       ~ MoveTextLineTest")
		self.SetCloseEvent(self.BeginBoi)

	def __LoadGUI(self):
		self.Biatch = ui.MoveTextLine()
		self.Biatch.SetParent(self)
		self.Biatch.SetText("TEST")
		self.Biatch.Show()

	def BeginBoi(self):
		self.Biatch.SetPosition(0, 0)
		self.Biatch.SetMoveSpeed(2.)
		(pgx, pgy) = self.GetGlobalPosition()
		self.Biatch.SetMovePosition(pgx + 175, pgy + 80)
		self.Biatch.SetEndMoveEvent(ui.__mem_func__(self.GetCancer))
		self.Biatch.MoveStart()

	def GetCancer(self):
		self.Hide()
		return 1

	def OnPressEscapeKey(self):
		self.GetCancer()
		return 1

class MoveImageBoxTest(ui.BoardWithTitleBar):
	def __init__(self):
		ui.BoardWithTitleBar.__init__(self)

		self.__LoadWindow()
		self.__LoadGUI()

	def __del__(self):
		ui.BoardWithTitleBar.__del__(self)

	def __LoadWindow(self):
		self.SetSize(200, 100)
		self.SetPosition(0, 0)
		self.SetCloseEvent(self.BeginBoi)
		self.SetTitleName("       ~ MoveImageBoxTest")
		self.AddFlag('movable')
		self.AddFlag('float')
		# self.SetCenterPosition()

	def __LoadGUI(self):
		self.Biatch = ui.MoveImageBox()
		self.Biatch.SetParent(proxy(self))
		self.Biatch.LoadImage("icon/item/trade.tga")
		self.Biatch.SetPosition(0,0)
		self.Biatch.AddFlag("float")
		self.Biatch.Show()

	def BeginBoi(self):
		self.Biatch.SetMoveSpeed(1.)
		(pgx, pgy) = self.GetGlobalPosition()
		self.Biatch.SetMovePosition(pgx + 175, pgy + 80)
		self.Biatch.SetEndMoveEvent(ui.__mem_func__(self.GetCancer))
		self.Biatch.MoveStart()

	def GetCancer(self):
		self.Hide()
		return 1

	def OnPressEscapeKey(self):
		self.GetCancer()
		return 1

class MoveScaleImageBoxTest(ui.BoardWithTitleBar):
	def __init__(self):
		ui.BoardWithTitleBar.__init__(self)

		self.Pivot = False
		self.__LoadWindow()
		self.__LoadGUI()

	def __del__(self):
		ui.BoardWithTitleBar.__del__(self)

	def __LoadWindow(self):
		self.SetSize(200, 100)
		self.SetPosition(0, 0)
		self.SetCloseEvent(self.BeginBoi)
		self.SetTitleName("       ~ MoveScaleImageBoxTest")
		self.AddFlag('movable')
		self.AddFlag('float')

	def __LoadGUI(self):
		self.Biatch = ui.MoveScaleImageBox()
		self.Biatch.SetParent(self)
		self.Biatch.LoadImage("icon/item/trade.tga")
		self.Biatch.SetScalePivotCenter(self.Pivot)
		self.Biatch.AddFlag("float")
		self.Biatch.Show()

	def BeginBoi(self):
		(pgx, pgy) = self.GetGlobalPosition()
		self.Biatch.SetPosition(0,0)
		self.Biatch.SetMovePosition(pgx+0, pgy+35)
		self.Biatch.SetMoveSpeed(1.5)
		self.Biatch.SetMaxScale(2.0)
		self.Biatch.SetMaxScaleRate(1.5)
		self.Biatch.MoveStart()
		self.Biatch.SetEndMoveEvent(ui.__mem_func__(self.Step0))

	def Step0(self):
		(pgx, pgy) = self.GetGlobalPosition()
		self.Biatch.SetPosition(0,35)
		self.Biatch.SetMovePosition(pgx+30, pgy+35)
		self.Biatch.SetMoveSpeed(1.5)
		self.Biatch.SetMaxScale(3.0)
		self.Biatch.SetMaxScaleRate(1.5)
		self.Biatch.MoveStart()
		self.Biatch.SetEndMoveEvent(ui.__mem_func__(self.Step1))

	def Step1(self):
		(pgx, pgy) = self.GetGlobalPosition()
		self.Biatch.SetPosition(30,35)
		self.Biatch.SetMovePosition(pgx+30, pgy+65)
		self.Biatch.SetMoveSpeed(1.5)
		self.Biatch.SetMaxScale(3.0)
		self.Biatch.SetMaxScaleRate(1.5)
		self.Biatch.MoveStart()
		self.Biatch.SetEndMoveEvent(ui.__mem_func__(self.Step2))

	def Step2(self):
		(pgx, pgy) = self.GetGlobalPosition()
		self.Biatch.SetPosition(30,65)
		self.Biatch.SetMovePosition(pgx+125, pgy+65)
		self.Biatch.SetMoveSpeed(1.5)
		self.Biatch.SetMaxScale(2.0)
		self.Biatch.SetMaxScaleRate(1.5)
		self.Biatch.MoveStart()
		self.Biatch.SetEndMoveEvent(ui.__mem_func__(self.Step3))

	def Step3(self):
		self.Biatch.SetPosition(125,65)

	def GetCancer(self):
		self.Hide()
		return 1

	def OnPressEscapeKey(self):
		self.GetCancer()
		return 1

 

 

PS: If I missed something just write a comment below.

  • Metin2 Dev 3
  • Love 21
Link to comment
Share on other sites

  • 4 years later...
  • Honorable Member
On 10/31/2018 at 2:09 PM, xP3NG3Rx said:

And I don't recommend to use the SetScalePivotCenter function, I don't know why but works a bit strange than the official, it needs something more during the texture load in.

Here is fix for SetScalePivotCenter:

First remove GrpImageInstance.cpp & GrpImageInstance.h.

Spoiler
///@@@EterLib/GrpExpandedImageInstance.cpp:
//Find
	if (0.0f == m_fRotation)

///Change
	if (0.0f == m_fRotation && !m_bScalePivotCenter)

///Add in void CGraphicExpandedImageInstance::Initialize()
	m_bScalePivotCenter = false;

///Add new funcs
const D3DXVECTOR2& CGraphicExpandedImageInstance::GetScale() const
{
	return m_v2Scale;
}

void CGraphicExpandedImageInstance::SetScalePivotCenter(bool bScalePivotCenter)
{
	m_bScalePivotCenter = bScalePivotCenter;
}
Spoiler
///@@@EterLib/GrpExpandedImageInstance.h:
//Find
		static CDynamicPool<CGraphicExpandedImageInstance>

///Add
	public:
		const D3DXVECTOR2& GetScale() const;
		void SetScalePivotCenter(bool bScalePivotCenter);
	private:
		bool m_bScalePivotCenter;
Spoiler
///@@@EterPythonLib/PythonWindow.cpp:

///paste the functions of the new classes anywhere you want
	/// CMoveTextLine
	CMoveTextLine::CMoveTextLine(PyObject * ppyObject) :
		CTextLine(ppyObject),
		m_v2SrcPos(0.0f, 0.0f),
		m_v2DstPos(0.0f, 0.0f),
		m_v2NextPos(0.0f, 0.0f),
		m_v2Direction(0.0f, 0.0f),
		m_v2NextDistance(0.0f, 0.0f),
		m_fDistance(0.0f),
		m_fMoveSpeed(10.0f),
		m_bIsMove(false)
	{
	}

	CMoveTextLine::~CMoveTextLine()
	{
	}

	DWORD CMoveTextLine::Type()
	{
		static DWORD s_dwType = GetCRC32("CMoveTextLine", strlen("CMoveTextLine"));
		return (s_dwType);
	}

	BOOL CMoveTextLine::OnIsType(DWORD dwType)
	{
		if (CMoveTextLine::Type() == dwType)
			return TRUE;

		return FALSE;
	}

	void CMoveTextLine::SetMoveSpeed(float fSpeed)
	{
		m_fMoveSpeed = fSpeed;
	}

	bool CMoveTextLine::GetMove()
	{
		return m_bIsMove;
	}

	void CMoveTextLine::MoveStart()
	{
		m_bIsMove = true;
		m_v2NextPos = m_v2SrcPos;
	}

	void CMoveTextLine::MoveStop()
	{
		m_bIsMove = false;
	}

	void CMoveTextLine::OnEndMove()
	{
		PyCallClassMemberFunc(m_poHandler, "OnEndMove", BuildEmptyTuple());
	}

	void CMoveTextLine::OnChangePosition()
	{
		m_TextInstance.SetPosition((GetDefaultCodePage() == CP_1256) ? m_rect.right : m_rect.left, m_rect.top);
	}

	void CMoveTextLine::SetMovePosition(float fDstX, float fDstY)
	{
		if (fDstX != m_v2DstPos.x || fDstY != m_v2DstPos.y || m_rect.left != m_v2SrcPos.x || m_rect.top != m_v2SrcPos.y)
		{
			m_v2SrcPos.x = m_rect.left;
			m_v2SrcPos.y = m_rect.top;

			m_v2DstPos.x = fDstX;
			m_v2DstPos.y = fDstY;

			D3DXVec2Subtract(&m_v2Direction, &m_v2DstPos, &m_v2SrcPos);

			m_fDistance = (m_v2Direction.y*m_v2Direction.y + m_v2Direction.x*m_v2Direction.x);
			D3DXVec2Normalize(&m_v2Direction, &m_v2Direction);

			if (m_v2SrcPos != m_v2NextPos)
			{
				float fDist = sqrtf(m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);
				m_v2NextPos = m_v2Direction * fDist;
				m_TextInstance.SetPosition(m_v2NextPos.x, m_v2NextPos.y);
			}
		}
	}

	void CMoveTextLine::OnUpdate()
	{
		if (IsShow() && GetMove())
		{
			D3DXVec2Add(&m_v2NextPos, &m_v2NextPos, &(m_v2Direction * m_fMoveSpeed));
			D3DXVec2Subtract(&m_v2NextDistance, &m_v2NextPos, &m_v2SrcPos);

			float fNextDistance = m_v2NextDistance.y * m_v2NextDistance.y + m_v2NextDistance.x * m_v2NextDistance.x;
			if (fNextDistance >= m_fDistance)
			{
				m_v2NextPos = m_v2DstPos;
				MoveStop();
				OnEndMove();
			}

			m_TextInstance.SetPosition(m_v2NextPos.x, m_v2NextPos.y);
			m_TextInstance.Update();
		}
	}

	void CMoveTextLine::OnRender()
	{
		if (IsShow())
			m_TextInstance.Render();
	}

	/// CMoveImageBox
	CMoveImageBox::CMoveImageBox(PyObject * ppyObject) :
		CImageBox(ppyObject),
		m_v2SrcPos(0.0f, 0.0f),
		m_v2DstPos(0.0f, 0.0f),
		m_v2NextPos(0.0f, 0.0f),
		m_v2Direction(0.0f, 0.0f),
		m_v2NextDistance(0.0f, 0.0f),
		m_fDistance(0.0f),
		m_fMoveSpeed(10.0f),
		m_bIsMove(false)
	{
	}

	CMoveImageBox::~CMoveImageBox()
	{
		OnDestroyInstance();
	}

	void CMoveImageBox::OnCreateInstance()
	{
		OnDestroyInstance();

		m_pImageInstance = CGraphicExpandedImageInstance::New();
	}

	void CMoveImageBox::OnDestroyInstance()
	{
		if (m_pImageInstance)
		{
			CGraphicExpandedImageInstance::Delete((CGraphicExpandedImageInstance*)m_pImageInstance);
			m_pImageInstance = NULL;
		}
	}

	DWORD CMoveImageBox::Type()
	{
		static DWORD s_dwType = GetCRC32("CMoveImageBox", strlen("CMoveImageBox"));
		return (s_dwType);
	}

	BOOL CMoveImageBox::OnIsType(DWORD dwType)
	{
		if (CMoveImageBox::Type() == dwType)
			return TRUE;

		return FALSE;
	}

	void CMoveImageBox::OnEndMove()
	{
		PyCallClassMemberFunc(m_poHandler, "OnEndMove", BuildEmptyTuple());
	}

	void CMoveImageBox::SetMovePosition(float fDstX, float fDstY)
	{
		if (fDstX != m_v2DstPos.x || fDstY != m_v2DstPos.y || m_rect.left != m_v2SrcPos.x || m_rect.top != m_v2SrcPos.y)
		{
			m_v2SrcPos.x = m_rect.left;
			m_v2SrcPos.y = m_rect.top;

			m_v2DstPos.x = fDstX;
			m_v2DstPos.y = fDstY;

			D3DXVec2Subtract(&m_v2Direction, &m_v2DstPos, &m_v2SrcPos);

			m_fDistance = (m_v2Direction.x*m_v2Direction.x + m_v2Direction.y*m_v2Direction.y);

			D3DXVec2Normalize(&m_v2Direction, &m_v2Direction);

			if (m_pImageInstance && m_v2SrcPos != m_v2NextPos)
			{
				float fDist = sqrtf(m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);

				m_v2NextPos = m_v2Direction * fDist;
				m_pImageInstance->SetPosition(m_v2NextPos.x, m_v2NextPos.y);
			}
		}
	}

	void CMoveImageBox::SetMoveSpeed(float fSpeed)
	{
		m_fMoveSpeed = fSpeed;
	}

	void CMoveImageBox::MoveStart()
	{
		m_bIsMove = true;
		m_v2NextPos = m_v2SrcPos;
	}

	void CMoveImageBox::MoveStop()
	{
		m_bIsMove = false;
	}

	bool CMoveImageBox::GetMove()
	{
		return m_bIsMove;
	}

	void CMoveImageBox::OnUpdate()
	{
		if (!m_pImageInstance)
			return;

		if (IsShow() && GetMove())
		{
			D3DXVec2Add(&m_v2NextPos, &m_v2NextPos, &(m_v2Direction * m_fMoveSpeed));
			D3DXVec2Subtract(&m_v2NextDistance, &m_v2NextPos, &m_v2SrcPos);

			float fNextDistance = (m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);
			if (fNextDistance >= m_fDistance)
			{
				m_v2NextPos = m_v2DstPos;
				MoveStop();
				OnEndMove();
			}

			m_pImageInstance->SetPosition(m_v2NextPos.x, m_v2NextPos.y);
		}
	}

	void CMoveImageBox::OnRender()
	{
		if (!m_pImageInstance)
			return;

		if (IsShow())
			m_pImageInstance->Render();
	}

	/// CMoveScaleImageBox
	CMoveScaleImageBox::CMoveScaleImageBox(PyObject * ppyObject) :
		CMoveImageBox(ppyObject),
		m_fMaxScale(1.0f),
		m_fMaxScaleRate(1.0f),
		m_fScaleDistance(0.0f),
		m_fAdditionalScale(0.0f),
		m_v2CurScale(1.0f, 1.0f)
	{
	}

	CMoveScaleImageBox::~CMoveScaleImageBox()
	{
		OnDestroyInstance();
	}

	void CMoveScaleImageBox::OnCreateInstance()
	{
		OnDestroyInstance();

		m_pImageInstance = CGraphicExpandedImageInstance::New();
	}

	void CMoveScaleImageBox::OnDestroyInstance()
	{
		if (m_pImageInstance)
		{
			CGraphicExpandedImageInstance::Delete((CGraphicExpandedImageInstance*)m_pImageInstance);
			m_pImageInstance = NULL;
		}
	}

	DWORD CMoveScaleImageBox::Type()
	{
		static DWORD s_dwType = GetCRC32("CMoveScaleImageBox", strlen("CMoveScaleImageBox"));
		return (s_dwType);
	}

	BOOL CMoveScaleImageBox::OnIsType(DWORD dwType)
	{
		if (CMoveScaleImageBox::Type() == dwType)
			return TRUE;

		return FALSE;
	}

	void CMoveScaleImageBox::SetMaxScale(float fMaxScale)
	{
		m_fMaxScale = fMaxScale;
	}

	void CMoveScaleImageBox::SetMaxScaleRate(float fMaxScaleRate)
	{
		m_fMaxScaleRate = fMaxScaleRate;
		float fDistanceRate = m_fDistance * fMaxScaleRate;
		m_fScaleDistance = fDistanceRate;
		m_v2CurScale = ((CGraphicExpandedImageInstance*)m_pImageInstance)->GetScale();
		float fDiffScale = m_fMaxScale - m_v2CurScale.x;
		m_fAdditionalScale = fDiffScale / (sqrtf(fDistanceRate) / m_fMoveSpeed);
	}

	void CMoveScaleImageBox::SetScalePivotCenter(bool bScalePivotCenter)
	{
		if (m_pImageInstance)
			((CGraphicExpandedImageInstance*)m_pImageInstance)->SetScalePivotCenter(bScalePivotCenter);
	}

	void CMoveScaleImageBox::OnUpdate()
	{
		if (!m_pImageInstance)
			return;

		if (IsShow() && GetMove())
		{
			D3DXVec2Add(&m_v2NextPos, &m_v2NextPos, &(m_v2Direction * m_fMoveSpeed));
			D3DXVec2Subtract(&m_v2NextDistance, &m_v2NextPos, &m_v2SrcPos);

			float fNextDistance = (m_v2NextDistance.x*m_v2NextDistance.x + m_v2NextDistance.y*m_v2NextDistance.y);
			if (m_fScaleDistance < fNextDistance)
				m_fAdditionalScale *= -1.0f;
			
			D3DXVECTOR2 v2NewScale;
			D3DXVec2Add(&v2NewScale, &((CGraphicExpandedImageInstance*)m_pImageInstance)->GetScale(), &D3DXVECTOR2(m_fAdditionalScale, m_fAdditionalScale));
			if (m_fMaxScale < v2NewScale.x)
				v2NewScale = D3DXVECTOR2(m_fMaxScale, m_fMaxScale);

			if (m_v2CurScale.x > v2NewScale.x)
				v2NewScale = m_v2CurScale;

			((CGraphicExpandedImageInstance*)m_pImageInstance)->SetScale(v2NewScale.x, v2NewScale.y);

			if (fNextDistance >= m_fDistance)
			{
				((CGraphicExpandedImageInstance*)m_pImageInstance)->SetScale(m_v2CurScale.x, m_v2CurScale.y);
				m_v2NextPos = m_v2DstPos;
				MoveStop();
				OnEndMove();
			}

			m_pImageInstance->SetPosition(m_v2NextPos.x, m_v2NextPos.y);
		}
	}

 

  • Metin2 Dev 3
  • Love 1
  • Love 1

 

Link to comment
Share on other sites

  • 4 weeks later...

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.