ariver1514 6 Posted January 5 Share Posted January 5 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 More sharing options...
ariver1514 6 Posted January 6 Author Share Posted January 6 Refresh: If someone also have client side version im interested Link to comment Share on other sites More sharing options...
Punszz 1 Posted January 8 Share Posted January 8 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 More sharing options...
ariver1514 6 Posted January 8 Author Share Posted January 8 (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 Sign In or Sign Up 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 January 8 by ariver1514 2 Link to comment Share on other sites More sharing options...
Punszz 1 Posted January 10 Share Posted January 10 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 Sign In or Sign Up 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() 1 Link to comment Share on other sites More sharing options...
ariver1514 6 Posted January 10 Author Share Posted January 10 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 More sharing options...
ariver1514 6 Posted Monday at 08:22 PM Author Share Posted Monday at 08:22 PM A little up Link to comment Share on other sites More sharing options...
ariver1514 6 Posted Tuesday at 12:16 PM Author Share Posted Tuesday at 12:16 PM 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 More sharing options...
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now