Jump to content
Maintenance : Final step ×

Element image on player target


Recommended Posts

Hello,

 

I have a little issue with the Element image on player target system here: 

https://metin2.dev/topic/17159-v175-element-image-on-target/

I have added the system on my files (TMP4 reference files),

everything works fine for monsters, but i can't manage to make it work for players.

Here are the modifications i made in my py files :

Spoiler

game.py:

Spoiler
if app.ENABLE_ELEMENT_TARGET:
		def SetHPTargetBoard(self, vid, hpPercentage, bElement):
			if vid != self.targetBoard.GetTargetVID():
				self.targetBoard.ResetTargetBoard()
				self.targetBoard.SetEnemyVID(vid)
			
			self.targetBoard.SetHP(hpPercentage)
			self.targetBoard.SetElementImage(bElement)
			self.targetBoard.Show()
	else:
		def SetHPTargetBoard(self, vid, hpPercentage):
			if vid != self.targetBoard.GetTargetVID():
				self.targetBoard.ResetTargetBoard()
				self.targetBoard.SetEnemyVID(vid)

			self.targetBoard.SetHP(hpPercentage)
			self.targetBoard.Show()

 

uitarget.py:

Spoiler

on top of the file:

Spoiler
import uiToolTip

if app.ENABLE_ELEMENT_TARGET:
	ELEMENT_IMAGE_DIC = {1: "elect", 2: "fire", 3: "ice", 4: "wind", 5: "earth", 6 : "dark"}

 

 def __init__(self):

Spoiler
		self.isShowButton = False
		if app.ENABLE_ELEMENT_TARGET:
			self.elementImage = None
			self.elementId = None
			self.elementImageToolTip = None

 

 def Close(self):

Spoiler
	def Close(self):
		self.__Initialize()
		if app.ENABLE_ELEMENT_TARGET and self.elementImage:
			self.elementImage.Hide()
		self.Hide()

 

def Destroy(self):

Spoiler
		self.hpGauge = None
		if app.ENABLE_ELEMENT_TARGET:
			self.elementImage = None
			self.elementId = None
			self.elementImageToolTip = None

 

def ResetTargetBoard(self):

Spoiler
		self.hpGauge.Hide()
		if app.ENABLE_ELEMENT_TARGET and self.elementImage:
			self.elementImage = None
			self.elementId = None
			if self.elementImageToolTip:
				self.elementImageToolTip.Hide()

 

And at the bottom of the file:
 

Spoiler
	if app.ENABLE_ELEMENT_TARGET:
		def SetElementImage(self, elementId):
			try:
				if elementId > 0 and elementId in ELEMENT_IMAGE_DIC.keys():
					self.elementId = elementId
					self.elementImage = ui.ExpandedImageBox()
					self.elementImage.SAFE_SetStringEvent("MOUSE_OVER_IN", self.OnElementImageOverIn)
					self.elementImage.SAFE_SetStringEvent("MOUSE_OVER_OUT", self.OnElementImageOverOut)
					self.elementImage.SetPosition(620, 50)	#position related change
					self.elementImage.LoadImage("d:/ymir work/ui/game/12zi/element/%s.sub" % (ELEMENT_IMAGE_DIC[elementId]))
					self.elementImage.SetScale(0.7, 0.7)	#official like img size
					self.elementImage.Show()
			except:
				pass

		def OnElementImageOverIn(self):
			if not self.elementImageToolTip:
				self.elementImageToolTip = uiToolTip.ToolTip()
			self.elementImageToolTip.ClearToolTip()
			self.elementImageToolTip.AppendTextLine(ELEMENT_IMAGE_DIC[self.elementId] + " element")
			self.elementImageToolTip.SetToolTipPosition(620, 130)	#position related change			
			self.elementImageToolTip.Show()

		def OnElementImageOverOut(self):
			if self.elementImageToolTip:
				self.elementImageToolTip.Hide()

 

 


 

Link to comment
Share on other sites

Add a ChatPacket into SetHPTargetBoard  and see the element value when u click on target player.  It's not enough to modify only python part..

The players don't have an element by default..  The players are equipped with resistance against elements. You might want to check what resistance an player has for a specific element?  

What u try to do make no sense.

Link to comment
Share on other sites

Posted (edited)
28 minutes ago, Punszz said:

Add a ChatPacket into SetHPTargetBoard  and see the element value when u click on target player.  It's not enough to modify only python part..

The players don't have an element by default..  The players are equipped with resistance against elements. You might want to check what resistance an player has for a specific element?  

What u try to do make no sense.

What I forgot to mention, my serverside IS from metin2 Factory topic but the part for players in the fonction IS from rakancito pendant system 

This is the hidden content, please

Basically : if a players wearing a pendant he will have the element associated to the element of his pendant.

Edit thank you for your answer

Edited by ariver1514
  • Metin2 Dev 2
Link to comment
Share on other sites

On 1/8/2025 at 1:14 PM, ariver1514 said:

What I forgot to mention, my serverside IS from metin2 Factory topic but the part for players in the fonction IS from rakancito pendant system 

This is the hidden content, please

Basically : if a players wearing a pendant he will have the element associated to the element of his pendant.

Edit thank you for your answer

The target need to wear pendant items. Make sure that the target wear pendat items and add a chatPacket so we can see what server send.

if app.ENABLE_ELEMENT_TARGET:
		def SetHPTargetBoard(self, vid, hpPercentage, bElement):
			import chat
			chat.AppendChat(chat.CHAT_TYPE_INFO, "Target element: {}".format(bElement))
			if vid != self.targetBoard.GetTargetVID():
				self.targetBoard.ResetTargetBoard()
				self.targetBoard.SetEnemyVID(vid)
			
			self.targetBoard.SetHP(hpPercentage)
			self.targetBoard.SetElementImage(bElement)
			self.targetBoard.Show()
	else:
		def SetHPTargetBoard(self, vid, hpPercentage):
			if vid != self.targetBoard.GetTargetVID():
				self.targetBoard.ResetTargetBoard()
				self.targetBoard.SetEnemyVID(vid)

			self.targetBoard.SetHP(hpPercentage)
			self.targetBoard.Show()

 

  • Love 1
Link to comment
Share on other sites

So I delete the metin2Factory system with serverside and thanks to the comment of XPenger and a little bit of chatGPT to convert (useful for translate code but so many things made wrong by the bot)  i used XPenger function to create the client part (for monsters only): 

So in PythonNonplayer.h:
I added in public:

DWORD    GetMonsterRaceFlag(DWORD dwVnum);


In Python NonPlayer.cpp:

 

DWORD CPythonNonPlayer::GetMonsterRaceFlag(DWORD dwVnum)
{
	const TMobTable* c_pTable = GetTable(dwVnum);
	if (!c_pTable)
		return 0;

	return c_pTable->dwRaceFlag;
}



And In PythonNonplayerModule.cpp:

PyObject* nonplayerGetAttElementFlagByVID(PyObject* poSelf, PyObject* poArgs) 
{
	int iVID;

	if (!PyTuple_GetInteger(poArgs, 0, &iVID))
		return Py_BuildException();

	CInstanceBase * pInstance = CPythonCharacterManager::Instance().GetInstancePtr(iVID);

	if (!pInstance)
		return Py_BuildValue("i", 0);

	DWORD dwVnum = pInstance->GetVirtualNumber();

	if (CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) >= 2048 && CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) < 4096)
		return Py_BuildValue("i", 1);
	if (CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) >= 4096 && CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) < 8192)
		return Py_BuildValue("i", 2);
	if (CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) >= 8192 && CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) < 16384)
		return Py_BuildValue("i", 3);
	if (CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) >= 16384 && CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) < 32768)
		return Py_BuildValue("i", 4);
	if (CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) >= 32768 && CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) < 65536)
		return Py_BuildValue("i", 5);
	if (CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) >= 65536 && CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) < 131072)
		return Py_BuildValue("i", 6);
	return Py_BuildValue("i", 0);
}


I add to create "GetMonsterRaceFlag" because "IsRaceflagByVnum" Would return the raceflag but they can't match what the function result would expect because lost of mobs have at least 2 raceflags and so the number the function retreive is the additioon of the values of raceflags, BUT I noticed every raceflag value is 2 times the previous raceflag on the list so : If a mob have Raceflag_att_elec: his raceflag is between 2048 and 4096 (without ever reaching 4096) even if he have every other previous raceflag on the raceflag list.
That's why i have made such ugly lines: 
if (CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) >= 65536 && CPythonNonPlayer::Instance().GetMonsterRaceFlag(dwVnum) < 131072)


My UiTarget.py client side is exactly the same that in root pack 2018.

Now im rocking my brain out to figure out how to do the same with Player module but im stuck because on penger function he reach pendant through PART_PENDANT in CRaceData but my PART_PENDANT is not present. Can someone help me from there ? Where do i have to write PART_PENDANT (Racedata.h ok but how to link it to pendant in CLient source or Server Source ?) I have see 2 place Serverside where it could be left but doesn't seems like it's working either.
I would love to use Getsubtype or another function in ItemData.h but I can't seems to make that work either...

Link to comment
Share on other sites

update:
I saw this comment from Xpengers:

So i kept my client side element target for Monster and for player i did it Server Side since i can't get playerGetElementByVID to work properly (because of PART_PENDANT so im still searching for it).

Server side :


char.cpp:

Spoiler
#ifdef ENABLE_ELEMENT_TARGET
	if (m_pkChrTarget && m_pkChrTarget->IsPC())
	{
		LPITEM pkElement = m_pkChrTarget->GetWear(WEAR_PENDANT);
		if (!pkElement) // NONE
			p.bElement = 0;
		else if (pkElement && (pkElement->GetVnum() >= 9600 && pkElement->GetVnum() <= 9800))
			p.bElement = 2;
		else if (pkElement && (pkElement->GetVnum() >= 9830 && pkElement->GetVnum() <= 10030))
			p.bElement = 3;
		else if (pkElement && (pkElement->GetVnum() >= 10060 && pkElement->GetVnum() <= 10260))
			p.bElement = 5;
		else if (pkElement && (pkElement->GetVnum() >= 10290 && pkElement->GetVnum() <= 10490))
			p.bElement = 6;
		else if (pkElement && (pkElement->GetVnum() >= 10520 && pkElement->GetVnum() <= 10720))
			p.bElement = 4;
		else if (pkElement && (pkElement->GetVnum() >= 10750 && pkElement->GetVnum() <= 10950))
			p.bElement = 1;
	}
	else
	{
		p.bElement = 0;
	}
#endif

	GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
}

 


Packet.h:

Spoiler
typedef struct packet_target
{
	BYTE	header;
	DWORD	dwVID;
	BYTE	bHPPercent;
#ifdef ENABLE_ELEMENT_TARGET
	BYTE	bElement;
#endif
} TPacketGCTarget;

 



Client Side:
 

Packet.h:

Spoiler
typedef struct packet_target
{
	BYTE	header;
	DWORD	dwVID;
	BYTE	bHPPercent;
#ifdef ENABLE_ELEMENT_TARGET
	BYTE	bElement;
#endif
} TPacketGCTarget;

 


PythonNetworkStreamPhaseGame.cpp:
 

Spoiler
bool CPythonNetworkStream::RecvTargetPacket()
{
	...
		if (!pInstTarget->IsDead())
		{
#ifdef ENABLE_ELEMENT_TARGET
			if (pInstTarget->IsPC())
				PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "ShowTargetElementEnchant", Py_BuildValue("(ii)", TargetPacket.dwVID, TargetPacket.bElement));
			else if (pInstTarget->IsBuilding())
				PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "CloseTargetBoardIfDifferent", Py_BuildValue("(i)", TargetPacket.dwVID));
#else
			if (pInstTarget->IsPC() && pInstTarget->IsBuilding())
				PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "CloseTargetBoardIfDifferent", Py_BuildValue("(i)", TargetPacket.dwVID));
#endif
			else if (pInstPlayer->CanViewTargetHP(*pInstTarget))
				PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetHPTargetBoard", Py_BuildValue("(ii)", TargetPacket.dwVID, TargetPacket.bHPPercent));

			....
		}
	}
...
}

 

 

 

Root py part:

 

game.py:

Spoiler
#search : 
def SetPCTargetBoard(self, vid, name):
  ...
  
#I added after:
def ShowTargetElementEnchant(self, bElement):		
		self.targetBoard.ShowElementImage(bElement)

 

 

Uitarget.py:
 

Spoiler
# in def __init__(self):

self.isShowButton = False
if app.ENABLE_ELEMENT_TARGET:
	self.elementImage = None
    
# in def Destroy(self):
self.hpGauge = None
if app.ENABLE_ELEMENT_TARGET:
	self.elementImage = None
    
# in Reset TargetBoard:
if app.ENABLE_ELEMENT_TARGET and self.elementImage:
	self.elementImage = None
    
# in def SetEnemyVID(self, vid):
self.SetTargetName(nameFront + name)
if app.ENABLE_ELEMENT_TARGET:
	self.HideAllElementImg()
	element = nonplayer.GetAttElementFlagByVID(vid)
	if element:
		self.ShowElementImage(element)
		self.elementImage.SetPosition(0, 40)
        
#at the end of file i added this:
if app.ENABLE_ELEMENT_TARGET:
	def ShowElementImage(self, elementID):
		if elementID > 0 and elementID in self.ELEMENT_IMG_PATH.keys():
			self.elementImage = ui.ExpandedImageBox()
			self.elementImage.SetParent(self)
			self.elementImage.LoadImage(self.ELEMENT_IMG_PATH[elementID])
			self.elementImage.SetPosition(0, 65)
			self.elementImage.SetScale(0.7, 0.7)
			self.elementImage.SetWindowHorizontalAlignLeft()
			self.elementImage.Show()

	def HideAllElementImg(self):		
		if self.elementImage:
			self.elementImage.Hide()

 

I don't think  this will be looked but if someone got an opinion about what i did i'll gladly take it to improve myself.

 

Best regards Ariver.
 

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • 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.