Jump to content

Search the Community

Showing results for tags 'python'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Metin2 Dev
    • Announcements
  • Community
    • Member Representations
    • Off Topic
  • Miscellaneous
    • Metin2
    • Showcase
    • File Requests
    • Community Support - Questions & Answers
    • Paid Support / Searching / Recruiting
  • Metin2 Development
  • Metin2 Development
    • Basic Tutorials / Beginners
    • Guides & HowTo
    • Binaries
    • Programming & Development
    • Web Development & Scripts / Systems
    • Tools & Programs
    • Maps
    • Quests
    • 3D Models
    • 2D Graphics
    • Operating Systems
    • Miscellaneous
  • Private Servers
    • Private Servers
  • Uncategorized
    • Drafts
    • Trash
    • Archive
    • Temporary
    • Metin2 Download

Product Groups

  • Small Advertisement
  • Large Advertisement
  • Advertising

Categories

  • Third Party - Providers Directory

Categories

  • Overview
  • Pages
    • Overview
    • File Formats
    • Network
    • Extensions

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Pillory


Marketplace


Game Server


Country


Nationality


Github


Gitlab


Discord


Skype


Website

  1. Hey M2DEV! Today I will show you how to fix one unpleasant error related to the auto attack. When you attack a monster automatically and for example want to move away from the monster, what do you do? Probably you will turn off the auto attack and try to move away from the monster using the WASD keys? Yes, but it won't work because the target doesn't reset when you try to disable the auto-attack. Before fix: [Hidden Content] After fix: [Hidden Content] Open file: UserInterface\PythonPlayer.h Make "__ClearAutoAttackTargetActorID();" public! Open file: UserInterface\PythonPlayerModulec.cpp We need to create a new method PyObject * playerClearAutoAttackTargetActorID(PyObject* poSelf, PyObject* poArgs) { CPythonPlayer::Instance().__ClearAutoAttackTargetActorID(); return Py_BuildNone(); } add method to s_methods[] { "ClearAutoAttackTargetActorID", playerClearAutoAttackTargetActorID, METH_VARARGS }, Compile bin! Open file: root/uitaskbar.py search elif self.EVENT_MOVE_AND_ATTACK == event: replace this part: elif self.EVENT_MOVE_AND_ATTACK == event: btn = self.mouseModeButtonList[dir].GetChild("button_move_and_attack") func = player.MBF_SMART player.ClearAutoAttackTargetActorID() tooltip_text = localeInfo.TASKBAR_ATTACK pack root file! P.S Please forgive me for my English, I use a GoogleTranslate
  2. M2 Download Center Download Here ( Internal ) Hi everyone, As title say, this is a wiki system but, InGame . This system was made by Kori . When i download it, the system had a bug on item bar, so, i've removed it . Screen of system: The system is open by pressing a key ( choosed for you ) . How to ? Well, 1º - Unpack your root . 2º- Search for archive game.py 3º- Open it and add: import uiwiki 4º - Search for: def __init__(self, stream): and add: self.wiki = uiwiki.AgeofPlatonWiki() 5º - Search for: onPressKeyDict[app.DIK_F5] and next add: onPressKeyDict[app.DIK_F9] = lambda : self.__OnWiki() Note: in here: [app.DIK_F9], F9 will be the key would you need to press to can view the system . You can change it , like you want. 6º - In the end of all ( game.py ) add this: def __OnWiki(self): if self.wiki.IsShow(): self.wiki.Hide() else: self.wiki.Show() 7º - Download the archive, add it to root, and pack it again . Download: Link Here Password: www.metin2dev.org Have fun ! Kind Regards, Grave
  3. M2 Download Center Download Here ( Internal ) Download Here ( GitHub ) Idea is from 2014 but I think this is good feature like discord. For open gui your name must start with "[" like [GM].
  4. Premise: I don't know whether you have this system from a free release elsewhere or you bought it and I have no idea if they are the same or not (even though the same version can be found in the first server files of Rubinum). There are two issues I was concerned with: -creating an item when you request the infos -putting the mob data dictionary in constinfo The first is if you have, in CreateDropItemVector function something like this: if (item) vec_item.push_back(item); So, we create an item and we do nothing with it, staying in memory for no purpose. Instead, we can use a vector of pairs. Open item_manager.h Replace bool CreateDropItemVector(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item); with: bool CreateDropItemVector(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<std::pair<int,int> > & vec_item); Now, open item_manager.cpp Replace bool ITEM_MANAGER::CreateDropItemVector(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item) With bool ITEM_MANAGER::CreateDropItemVector(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<std::pair<int,int> > & vec_item) and remove LPITEM item = NULL; and edit the function accordingly. EX for common_drop_item, replace: std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin(); while (it != g_vec_pkCommonDropItem[bRank].end()) { const CItemDropInfo & c_rInfo = *(it++); if (iLevel < c_rInfo.m_iLevelStart || iLevel > c_rInfo.m_iLevelEnd) continue; TItemTable * table = GetTable(c_rInfo.m_dwVnum); if (!table) continue; item = NULL; if (table->bType == ITEM_POLYMORPH) { if (c_rInfo.m_dwVnum == pkChr->GetPolymorphItemVnum()) { item = CreateItem(c_rInfo.m_dwVnum, 1, 0, true); if (item) item->SetSocket(0, pkChr->GetRaceNum()); } } else item = CreateItem(c_rInfo.m_dwVnum, 1, 0, true); if (item) vec_item.push_back(item); } with std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin(); while (it != g_vec_pkCommonDropItem[bRank].end()) { const CItemDropInfo & c_rInfo = *(it++); if (iLevel < c_rInfo.m_iLevelStart || iLevel > c_rInfo.m_iLevelEnd) continue; TItemTable * table = GetTable(c_rInfo.m_dwVnum); if (!table) continue; if(c_rInfo.m_dwVnum > 70103 && c_rInfo.m_dwVnum < 70108) { if (c_rInfo.m_dwVnum != pkChr->GetPolymorphItemVnum()) { continue; } } vec_item.push_back(std::make_pair(c_rInfo.m_dwVnum, 1)); } (edit 70103 and 70108 accordingly with your Polymorph Marble vnums The whole function should look like this: bool ITEM_MANAGER::CreateDropItemVector(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<std::pair<int,int> > & vec_item) { if (pkChr->IsPolymorphed() || pkChr->IsPC()) { return false; } int iLevel = pkKiller->GetLevel(); BYTE bRank = pkChr->GetMobRank(); std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin(); while (it != g_vec_pkCommonDropItem[bRank].end()) { const CItemDropInfo & c_rInfo = *(it++); if (iLevel < c_rInfo.m_iLevelStart || iLevel > c_rInfo.m_iLevelEnd) continue; TItemTable * table = GetTable(c_rInfo.m_dwVnum); if (!table) continue; if(c_rInfo.m_dwVnum > 70103 && c_rInfo.m_dwVnum < 70108) { if (c_rInfo.m_dwVnum != pkChr->GetPolymorphItemVnum()) { continue; } } vec_item.push_back(std::make_pair(c_rInfo.m_dwVnum, 1)); } // Drop Item Group { itertype(m_map_pkDropItemGroup) it; it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum()); if (it != m_map_pkDropItemGroup.end()) { typeof(it->second->GetVector()) v = it->second->GetVector(); for (DWORD i = 0; i < v.size(); ++i) { vec_item.push_back(std::make_pair(v[i].dwVnum, v[i].iCount)); } } } // MobDropItem Group { itertype(m_map_pkMobItemGroup) it; it = m_map_pkMobItemGroup.find(pkChr->GetRaceNum()); if ( it != m_map_pkMobItemGroup.end() ) { CMobItemGroup* pGroup = it->second; if (pGroup && !pGroup->IsEmpty()) { const CMobItemGroup::SMobItemGroupInfo& info = pGroup->GetOne(); vec_item.push_back(std::make_pair(info.dwItemVnum, info.iCount)); } } } // Level Item Group { itertype(m_map_pkLevelItemGroup) it; it = m_map_pkLevelItemGroup.find(pkChr->GetRaceNum()); if ( it != m_map_pkLevelItemGroup.end() ) { if ( it->second->IsInLevelRange((DWORD)iLevel) ) { typeof(it->second->GetVector()) v = it->second->GetVector(); for ( DWORD i=0; i < v.size(); i++ ) { DWORD dwVnum = v[i].dwVNum; vec_item.push_back(std::make_pair(dwVnum, v[i].iCount)); } } } } // ETC DropItem if (pkChr->GetMobDropItemVnum()) { itertype(m_map_dwEtcItemDropProb) it = m_map_dwEtcItemDropProb.find(pkChr->GetMobDropItemVnum()); if (it != m_map_dwEtcItemDropProb.end()) { vec_item.push_back(std::make_pair(pkChr->GetMobDropItemVnum(), 1)); } } //Metin if (pkChr->IsStone()) { if (pkChr->GetDropMetinStoneVnum()) { vec_item.push_back(std::make_pair(pkChr->GetDropMetinStoneVnum(), 1)); } } return vec_item.size(); } Note: level item group and drop item group might be different because in my files i have a level_limit_max token and, for drop_item_group, I don't expect to put a Polymorph Marble. Also it's missing the buyertheifgloves item group, but you can clearly see the pattern and modify accordingly. Edit : I found a bug in the mob_drop_item infos. If you don't know, with the type "kill", you drop only one of the items you put in the list, so the info drop, well, will show only one, and then another, and another one, every time you reopen it. To fix this issue, go to item_manager.h and search for: const SMobItemGroupInfo& GetOne() const { return m_vecItems[GetOneIndex()]; } Add after: std::vector<std::pair<int,int>> GetVector() { std::vector<std::pair<int,int>> item_list; for(auto &x : m_vecItems) item_list.emplace_back(std::make_pair(x.dwItemVnum,x.iCount)); return item_list; } then, in item_manager.cpp, instead of: if (pGroup && !pGroup->IsEmpty()) { const CMobItemGroup::SMobItemGroupInfo& info = pGroup->GetOne(); vec_item.push_back(std::make_pair(info.dwItemVnum, info.iCount)); } replace it with: if (pGroup && !pGroup->IsEmpty()) { auto vec_items = pGroup->GetVector(); for(auto &x : vec_items) vec_item.push_back(std::make_pair(x.first,x.second)); } Side Note (how to add drop of the Stones from Metins server side): Before return vec_item.size(); you can also organize the vector as you want or create another one with a certain structure, like, first the common drop items, then the advance items or whatever, you can also clear it for what I care. Me, for example, I sort it to have all the vnums from the smallest to the largest. You can do that by: std::sort(vec_item.begin(), vec_item.end(), std::less<std::pair<int,int> >()); Now, let's go to input_main.cpp Remove: LPITEM pkInfoItem; We don't use an item anymore, remember? So now replace: static std::vector<LPITEM> s_vec_item; with: static std::vector<std::pair<int,int> > s_vec_item; Then replace: if (ITEM_MANAGER::instance().CreateDropItemVector(m_pkChrTarget, ch, s_vec_item) && (m_pkChrTarget->IsMonster() || m_pkChrTarget->IsStone())) with: if ((m_pkChrTarget->IsMonster() || m_pkChrTarget->IsStone()) && ITEM_MANAGER::instance().CreateDropItemVector(m_pkChrTarget, ch, s_vec_item)) This way also, if you target a player or a NPC, it will not trigger the CreateDropItemVector function. Remove everything inside the function if (s_vec_item.size() == 0); //this is useless else if (s_vec_item.size() == 1) //even more useless Just put: for(std::vector<std::pair<int,int> >::const_iterator iter = s_vec_item.begin(); iter != s_vec_item.end();++iter) { pInfo.dwVID = m_pkChrTarget->GetVID(); pInfo.race = m_pkChrTarget->GetRaceNum(); pInfo.dwVnum = iter->first; pInfo.count = iter->second; ch->GetDesc()->Packet(&pInfo, sizeof(TPacketGCTargetInfo)); } That's it. Now the constinfo issue. So, open constinfo.py and remove: import app if app.ENABLE_SEND_TARGET_INFO: MONSTER_INFO_DATA = {} Open uitarget.py and after the imports add: MONSTER_INFO_DATA = {} and replace whatever declaration with constinfo.MONSTER_INFO_DATA with just MONSTER_INFO_DATA Now open game.py. Even here, replace constinfo.MONSTER_INFO_DATA with uiTarget.MONSTER_INFO_DATA Last little fix, open intrologin.py Search for: self.stream.SetLoginInfo(id, pwd) the one in: def __OnClickLoginButton(self): add before uiTarget.MONSTER_INFO_DATA.clear() This should fix the issue when you don't close the client and, if you change the drop, you still see the older drop. Now you may ask, why all the other servers who may have this have never crashed or imploded? To be fair, I don't know and I don't care. Just know, if your system is similar to this, be aware of the issues and that this is one but definitely not the only fix possible.
  5. Hi, i made some changes on this system so that it now can show multiple accounts slots and add/delete accounts easily I'm not an experienced programmer by any means, so bugs might happen and the code isn't the most efficient and clean, so if anyone has a suggestion let me know! [Hidden Content] First i recommend installing his system first because i will only be listing the changes i made and this wont work without his system installed first Also, i will only show the steps to have 2 slots account, but they can easily be replicated to have multiple accounts. Implemented and Tested on TMP4 Server Files but most likely will work on any other server files. Be extremely careful with tabulations, i would recommend using Visual Studio Code or something similar to avoid problems with it Small video: Icons used for save and delete account button (it doesn't have on hover and on click icons so you will have to add them yourself) Download -> Mediafire or M2DL So lets start First delete the root/uiSelectCredentials.py and uiscript/accountlistwindow files that wont be needed anymore root/introwindow.py (This is configured for my own interface so you will have to change positions according to yours) root/intrologin.py (Remember you need to have the system from North implemented or you wont be able to find the correct lines) I think i'm not missing anything but if you find any error let me know and i will update the post. Probably gonna try to do some changes on the code to make it easier to add more accounts, currently it's not that hard but can be better. Feel free to leave suggestions and help improve this!
  6. Download Alternative download links → Mega Hello Metin2 Dev. I'm here to present a Premium System. How does it work? Once use item, player gets Permanent Premium. Since this is V1, it only allows the player to expand the bravery cape. Premium shows it's activated on above left corner. Players can only activate Premium on certain maps (I chose City 1 of each kingdom, but you can choose other). In case of any problem, report here and i'll fix it.
  7. M2 Download Center Download Here ( Internal ) Hello, im here today releasing my version of slot effect system. Is not the same as the official looks like but in the future i will update this to look the same. Screenshot to see how it looks like. Everything in this system was made by me. Tutorial: Go to UserInterface > PythonPlayer.cpp Search for : void CPythonPlayer::SetItemData(TItemPos Cell, const TItemData & c_rkItemInst) Add in the end of the funcion: PyCallClassMemberFunc(m_ppyGameWindow, "OnNewItem", Py_BuildValue("(i)", Cell.cell)); Compile It. Go to root > constInfo.py Add this somewhere: NEWITEMS = [] Save it. Go to root > game.py Add this function: def OnNewItem(self, cell): if not cell in constInfo.NEWITEMS: constInfo.NEWITEMS.append(cell) Save It. Go to root > uiinventory.py Search for : def RefreshBagSlotWindow(self): Add this before this: (if 0 == itemCount:) : if itemCount == 0 and slotNumber in constInfo.NEWITEMS: constInfo.NEWITEMS.remove(slotNumber) Add this under this: (setItemVNum(i, itemVnum, itemCount)) : self.wndItem.EnableCoverButton(i) if slotNumber in constInfo.NEWITEMS: self.wndItem.SetCoverButton(i, "d:/ymir work/ui/game/quest/slot_button_00.sub",\ "d:/ymir work/ui/game/quest/slot_button_00.sub",\ "d:/ymir work/ui/game/quest/slot_button_00.sub",\ "d:/ymir work/ui/new_icon.tga", FALSE, FALSE) self.wndItem.DisableCoverButton(i) Search for: def OverInItem(self, overSlotPos): Add under: slotPos = overSlotPos Add in the end: if overSlotPos in constInfo.NEWITEMS: self.wndItem.EnableCoverButton(slotPos) constInfo.NEWITEMS.remove(overSlotPos) Save It. Finally go to ymirwork/ui and add this file: [Hidden Content] Pack root and etc. Have fun This may not be the most optimized way to do this system, but at least you have a way. In the future i will post more updates such as a more optimized versions and with official effects. If you find any bugs please post it. #UPDATE Kind Regards, Frozen
  8. Download Alternative download links → Github You need to have installed python (Is up till 3.9) After install uncompile6 pip install --upgrade uncompyle6 Command prompt. cd ur/path/... python.exe PYCtoPY.py
  9. M2 Download Center Download Here ( Internal ) ### 0.1 Root / uiMessenger.py: # 1. Search: def OnLogin(self, groupIndex ... # 1. After: member.Online() self.OnRefreshList() # 1. Add: if not name in constInfo.ALREADY_NOTIFY_LIST: self.onlinePopup = uiCommon.OnlinePopup() self.onlinePopup.SetUserName(name) self.onlinePopup.SetEvent(ui.__mem_func__(self.OpenWhisper), "MOUSE_LEFT_BUTTON_UP", name) self.onlinePopup.SlideIn() constInfo.ALREADY_NOTIFY_LIST.append(name) # 1.1 After: def OnLogin(... Add: def OpenWhisper(self, eventType, userName): self.whisperButtonEvent(userName) ### 0.2 Root / constInfo.py: # 2. Add: ALREADY_NOTIFY_LIST = [] ### 0.3 Root / ui.py # 3 Search: class Board(Window): (....) # 3 REPLACE this class with: class Board(Window): CORNER_WIDTH = 32 CORNER_HEIGHT = 32 LINE_WIDTH = 128 LINE_HEIGHT = 128 LT = 0 LB = 1 RT = 2 RB = 3 L = 0 R = 1 T = 2 B = 3 BASE_PATH = "d:/ymir work/ui/pattern" IMAGES = { 'CORNER' : { 0 : "Board_Corner_LeftTop", 1 : "Board_Corner_LeftBottom", 2 : "Board_Corner_RightTop", 3 : "Board_Corner_RightBottom" }, 'BAR' : { 0 : "Board_Line_Left", 1 : "Board_Line_Right", 2 : "Board_Line_Top", 3 : "Board_Line_Bottom" }, 'FILL' : "Board_Base" } def __init__(self, layer = "UI"): Window.__init__(self, layer) self.skipMaxCheck = False self.MakeBoard() def MakeBoard(self): CornerFileNames = [ ] LineFileNames = [ ] for imageDictKey in (['CORNER', 'BAR']): for x in xrange(len(self.IMAGES[imageDictKey])): if imageDictKey == "CORNER": CornerFileNames.append("%s/%s.tga" % (self.BASE_PATH, self.IMAGES[imageDictKey][x])) elif imageDictKey == "BAR": LineFileNames.append("%s/%s.tga" % (self.BASE_PATH, self.IMAGES[imageDictKey][x])) self.Corners = [] for fileName in CornerFileNames: Corner = ExpandedImageBox() Corner.AddFlag("not_pick") Corner.LoadImage(fileName) Corner.SetParent(self) Corner.SetPosition(0, 0) Corner.Show() self.Corners.append(Corner) self.Lines = [] for fileName in LineFileNames: Line = ExpandedImageBox() Line.AddFlag("not_pick") Line.LoadImage(fileName) Line.SetParent(self) Line.SetPosition(0, 0) Line.Show() self.Lines.append(Line) self.Lines[self.L].SetPosition(0, self.CORNER_HEIGHT) self.Lines[self.T].SetPosition(self.CORNER_WIDTH, 0) self.Base = ExpandedImageBox() self.Base.AddFlag("not_pick") self.Base.LoadImage("%s/%s.tga" % (self.BASE_PATH, self.IMAGES['FILL'])) self.Base.SetParent(self) self.Base.SetPosition(self.CORNER_WIDTH, self.CORNER_HEIGHT) self.Base.Show() def __del__(self): Window.__del__(self) def SetSize(self, width, height): if not self.skipMaxCheck: width = max(self.CORNER_WIDTH*2, width) height = max(self.CORNER_HEIGHT*2, height) Window.SetSize(self, width, height) self.Corners[self.LB].SetPosition(0, height - self.CORNER_HEIGHT) self.Corners[self.RT].SetPosition(width - self.CORNER_WIDTH, 0) self.Corners[self.RB].SetPosition(width - self.CORNER_WIDTH, height - self.CORNER_HEIGHT) self.Lines[self.R].SetPosition(width - self.CORNER_WIDTH, self.CORNER_HEIGHT) self.Lines[self.B].SetPosition(self.CORNER_HEIGHT, height - self.CORNER_HEIGHT) verticalShowingPercentage = float((height - self.CORNER_HEIGHT*2) - self.LINE_HEIGHT) / self.LINE_HEIGHT horizontalShowingPercentage = float((width - self.CORNER_WIDTH*2) - self.LINE_WIDTH) / self.LINE_WIDTH self.Lines[self.L].SetRenderingRect(0, 0, 0, verticalShowingPercentage) self.Lines[self.R].SetRenderingRect(0, 0, 0, verticalShowingPercentage) self.Lines[self.T].SetRenderingRect(0, 0, horizontalShowingPercentage, 0) self.Lines[self.B].SetRenderingRect(0, 0, horizontalShowingPercentage, 0) if self.Base: self.Base.SetRenderingRect(0, 0, horizontalShowingPercentage, verticalShowingPercentage) # 3 AFTER CLASS BOARD ADD THIS CLASS: class BorderB(Board): CORNER_WIDTH = 16 CORNER_HEIGHT = 16 LINE_WIDTH = 16 LINE_HEIGHT = 16 BASE_PATH = "d:/ymir work/ui/pattern" IMAGES = { 'CORNER' : { 0 : "border_b_left_top", 1 : "border_b_left_bottom", 2 : "border_b_right_top", 3 : "border_b_right_bottom" }, 'BAR' : { 0 : "border_b_left", 1 : "border_b_right", 2 : "border_b_top", 3 : "border_b_bottom" }, 'FILL' : "border_b_center" } def __init__(self): Board.__init__(self) self.eventFunc = { "MOUSE_LEFT_BUTTON_UP" : None, } self.eventArgs = { "MOUSE_LEFT_BUTTON_UP" : None, } def __del__(self): Board.__del__(self) self.eventFunc = None self.eventArgs = None def SetSize(self, width, height): Board.SetSize(self, width, height) def SetEvent(self, func, *args) : result = self.eventFunc.has_key(args[0]) if result : self.eventFunc[args[0]] = func self.eventArgs[args[0]] = args else : print "[ERROR] ui.py SetEvent, Can`t Find has_key : %s" % args[0] def OnMouseLeftButtonUp(self): if self.eventFunc["MOUSE_LEFT_BUTTON_UP"] : apply(self.eventFunc["MOUSE_LEFT_BUTTON_UP"], self.eventArgs["MOUSE_LEFT_BUTTON_UP"]) ### 0.4 Root / uiCommon.py # 4 Add this to the end of file: ### (Check if you have in this file import app ) class OnlinePopup(ui.BorderB): def __init__(self): ui.BorderB.__init__(self) self.isActiveSlide = False self.isActiveSlideOut = False self.endTime = 0 self.wndWidth = 0 self.textLine = ui.TextLine() self.textLine.SetParent(self) self.textLine.SetWindowHorizontalAlignCenter() self.textLine.SetWindowVerticalAlignCenter() self.textLine.SetHorizontalAlignCenter() self.textLine.SetVerticalAlignCenter() self.textLine.SetPosition(13, 0) self.textLine.Show() self.onlineImage = ui.ImageBox() self.onlineImage.SetParent(self) self.onlineImage.SetPosition(8, 8) self.onlineImage.LoadImage("d:/ymir work/ui/game/windows/messenger_list_online.sub") self.onlineImage.Show() def __del__(self): ui.BorderB.__del__(self) def SlideIn(self): self.SetTop() self.Show() self.isActiveSlide = True self.endTime = app.GetGlobalTimeStamp() + 5 def Close(self): self.Hide() def Destroy(self): self.Close() def SetUserName(self, name): self.textLine.SetText("Player %s is online." % str(name)) self.wndWidth = self.textLine.GetTextSize()[0] + 40 self.SetSize(self.wndWidth, 25) self.SetPosition(-self.wndWidth, wndMgr.GetScreenHeight() - 200) def OnUpdate(self): if self.isActiveSlide and self.isActiveSlide == True: x, y = self.GetLocalPosition() if x < 0: self.SetPosition(x + 4, y) if self.endTime - app.GetGlobalTimeStamp() <= 0 and self.isActiveSlideOut == False and self.isActiveSlide == True: self.isActiveSlide = False self.isActiveSlideOut = True if self.isActiveSlideOut and self.isActiveSlideOut == True: x, y = self.GetLocalPosition() if x > -(self.wndWidth): self.SetPosition(x - 4, y) if x <= -(self.wndWidth): self.isActiveSlideOut = False self.Close() ######## Please write in topic If i forgot something. ######## Images for board: [Hidden Content]
  10. Maybe many of you didn't even notice or just don't mind showing that "info" when you hover your mouse over an NPC, guild spot, portal, etc.. To get rid of text overlap with other "squares" on the minimap, I created a display, immediately below the window, which indicates in a much more airy way the name and coordinates of a point on the map. I know that maybe for many it seems like a easy thing and/or they didn't use the directions provided anyway, but for others it might even be a plus. I leave you with a final sentence: Details make the difference! Tutorial: atlaswindow.py (uiscript.eix/.epk) [Hidden Content] uiminimap.py (root.eix/.epk) [Hidden Content] I welcome any kind of feedback from you and if anyone tries this display mode, don't forget to post a picture here as well.
  11. M2 Download Center Download Here ( Internal ) Hello, This little thing is marks your pet seal into your inventory like the autopotion. This arrives with the v17.5 patch. Open PetSystem.cpp and replace or make it fit for you: void CPetActor::SetSummonItem(LPITEM pItem) { if (NULL == pItem) { LPITEM pSummonItem = ITEM_MANAGER::instance().FindByVID(m_dwSummonItemVID); if (NULL != pSummonItem) pSummonItem->SetSocket(1, FALSE); m_dwSummonItemVID = 0; m_dwSummonItemVnum = 0; return; } pItem->SetSocket(1, TRUE); m_dwSummonItemVID = pItem->GetVID(); m_dwSummonItemVnum = pItem->GetVnum(); } After that open the uiInventory.py and paste this code below the autopotion if-statement in the RefreshBagSlotWindow function. elif itemVnum >= 53001 and itemVnum <= 53256: metinSocket = [player.GetItemMetinSocket(globalSlotNumber, j) for j in xrange(player.METIN_SOCKET_MAX_NUM)]# <!> globalSlotNumber may be different <!> isActivated = 0 != metinSocket[1] if isActivated: self.wndItem.ActivateSlot(i) else: self.wndItem.DeactivateSlot(i)
  12. M2 Download Center Download Here ( Internal ) Hello everyone. I've got this request long time ago to extend the OutLine coloring feature for the TextLines to make beautiful texts via Python. As you might know there is the ConquerorLevel text which also uses this feature just binary sided. With this small code you will be able to recolor the OutLine of the textlines from python scripts. Demo: Guide: Test Script: Any problem --> Comment below Greetz
  13. Script for scanning and automatically removing definitions Remove.cpp import os folder_path = '/txt/src' encoding = 'latin1' definition_to_remove = '#ifdef __ENABLE_OFFLINE_SHOP__' for root, dirs, files in os.walk(folder_path): for file in files: if file.endswith('.cpp') or file.endswith('.h'): file_path = os.path.join(root, file) with open(file_path, 'r', encoding=encoding) as f: lines = f.readlines() with open(file_path, 'w', encoding=encoding) as f: remove_lines = False for line in lines: if definition_to_remove in line: remove_lines = True if remove_lines: if '#endif' in line: remove_lines = False continue f.write(line) Remove if app. import os directory = '/txt/src' encoding = 'latin1' target_if = 'if app.ENABLE_OFFLINE_SHOP:' for filename in os.listdir(directory): if filename.endswith('.py'): filepath = os.path.join(directory, filename) with open(filepath, 'r', encoding=encoding) as f: lines = f.readlines() with open(filepath, 'w', encoding=encoding) as f: in_target_block = False target_indent = 0 for line in lines: indent = len(line) - len(line.lstrip()) if target_if in line: in_target_block = True target_indent = indent elif in_target_block and indent > target_indent: continue else: in_target_block = False f.write(line)
  14. Greetings everyone, I am delighted to share with you my first post. While it may not be groundbreaking, I hope that it will be useful to someone. Typically, to view your exact percentage of EXP, HP, and SP, you need to hover your mouse over the "container" - essentially, this works as a tooltip. However, as I am currently working on a new interface, I decided to change this. By implementing the following code, the experience percentage will always be displayed on the screen, making it more user-friendly, in my opinion. The same goes for HP and SP, although I have chosen to display only their current values. Please note that the (x,y) coordinates provided are simply an example of where the text will appear on the screen. Feel free to adjust them as needed. PS: I have added the level next to the experience percentage on the left side. root/uitaskbar.py ---> Add the following classes: class ExperienceDisplay: #added display level on this class def __init__(self): self.percentage_text = ui.TextLine() self.percentage_text.SetPosition(100, 40) self.percentage_text.SetHorizontalAlignCenter() self.percentage_text.Hide() self.level_text = ui.TextLine() self.level_text.SetPosition(60,40) self.level_text.SetHorizontalAlignCenter() self.level_text.Hide() def UpdateExperiencePercentage(self, percentage): self.percentage_text.SetText("{:.2f}%".format(percentage)) self.percentage_text.SetFontColor(1.0, 1.0, 0.0) #yellow self.percentage_text.Show() level = player.GetStatus(player.LEVEL) self.level_text.SetText("Lv. " + str(level) + " - ") self.level_text.SetFontColor(1.0, 1.0, 0.0) self.level_text.Show() class HPDisplay: def __init__(self): self.curPoint_text = ui.TextLine() self.curPoint_text.SetPosition(100, 70) self.curPoint_text.SetHorizontalAlignCenter() self.curPoint_text.Hide() def update_hp_text(self, curPoint): self.curPoint_text.SetText("HP: " + str(curPoint)) self.curPoint_text.SetFontColor(1.0, 0.0, 0.0) #red self.curPoint_text.Show() class SPDisplay: def __init__(self): self.curPoint_text = ui.TextLine() self.curPoint_text.SetPosition(100, 100) self.curPoint_text.SetHorizontalAlignCenter() self.curPoint_text.Hide() def update_sp_text(self, curPoint): self.curPoint_text.SetText("SP: " + str(curPoint)) self.curPoint_text.SetFontColor(0.0, 0.0, 1.0) #blue self.curPoint_text.Show() Search: self.tooltipEXP.SetText("%s : %.2f%%" % (localeInfo.TASKBAR_EXP, float(curPoint) / max(1, float(maxPoint)) * 100)) Replace with: self.experience_display = ExperienceDisplay() self.experience_display.UpdateExperiencePercentage(float(curPoint) / max(1, float(maxPoint)) * 100) Search: self.tooltipHP.SetText("%s : %d / %d" % (localeInfo.TASKBAR_HP, curPoint, maxPoint)) Replace with: self.hpdisplay = HPDisplay() self.hpdisplay.update_hp_text(curPoint) Search: self.tooltipSP.SetText("%s : %d / %d" % (localeInfo.TASKBAR_SP, curPoint, maxPoint)) Replace with: self.spdisplay = SPDisplay() self.spdisplay.update_sp_text(curPoint) That's all, if I missed something please tell me. Screenshot
  15. [Hidden Content] [Hidden Content] Reversed from 22.2.7.0 Official Binary. + Football Metin Stone From 22.5.7.0: Functions were in different modules, I gathered them on a single module. Do not forget to get proto and other files for metin stones from official packs.
  16. Video: Code: def convert_to_quest(input_text, quest_name, state_name, npc_id, chat_option): quest_code = f"quest {quest_name} begin\n\tstate {state_name} begin\n\t\twhen {npc_id}.chat.\"{chat_option}\" begin\n" lines = input_text.split('\n') indentation_level = 0 for line in lines: stripped_line = line.strip() if stripped_line.startswith("end"): indentation_level -= 1 stripped_line = stripped_line.replace(" (", "(").replace(" )", ")") stripped_line = stripped_line.replace(" . ", ".") stripped_line = stripped_line.replace(' "', '"') indent = '\t' * (3 + indentation_level) quest_code += f"{indent}{stripped_line}\n" if stripped_line.startswith(("if", "while", "for")) and "end" not in stripped_line: indentation_level += 1 quest_code += "\t\tend\n\tend\nend" return quest_code def process_script_file(script_file_name, quest_name, state_name, npc_id, chat_option): with open(script_file_name, 'r', encoding='latin1') as f: input_text = f.read() quest_code = convert_to_quest(input_text, quest_name, state_name, npc_id, chat_option) quest_file_name = script_file_name.replace('.script', '.quest') with open(quest_file_name, 'w', encoding='latin1') as f: f.write(quest_code) process_script_file('marriage_manage.start.0.script', 'weeding', 'start', 20358, 'Oldwoman')
  17. Hi all, this is a simple and silly code for those who want to enchant objects with countdown. I used real_time, so I put the objects inside a chest. The time will start running when you open the chest. I hope something similar has not already been shared, in case I apologize. If I have forgotten something in creating the code please let me know. [Hidden Content] or [Hidden Content] [Hidden Content]
  18. The client is freezing for a while(anywhere from a few ms to multiple seconds for slower PCs) when meeting a new NPC/enemy for the first time because that's when it registers, creates and loads the entity. Note: This is only a partial fix. Why is it partial? Because it only loads the static mobs and NPCs available in the map(npc, regen, boss, group and group_group), so it won't fix the problem for dynamic entities, like pets and mounts. It can be extended to load those as well, of course, but you'll have to take care of that on your own. Variant: A way of completely fixing this would be to create the instances and load their files after registering the path(in root->playerSettingModule->LoadGameNPC), BUT that would slow down the initial loading quite a bit, since it'll load ALL mobs/npcs/pets/mounts, even if most of them will never be used. There's advantages and drawbacks to both methods. Choose for yourself. Here's the link: [or] [Hidden Content] [or] [Hidden Content] Good luck! - Amun Edit: UPDATE 08/12/2022: 1. Refactored to use unordered_set from the beginning instead of creating a vector, then filtering unique entities by creating a set, and then moving them back to a vector. 2. Extended to load the full spectrum of entities(both static and dynamic), except for PC(which are loaded in loading phase), WARP, GOTO, and DOOR. They can be included by altering this block in char_manager.cpp: #ifdef ENABLE_ENTITY_PRELOADING //@Amun: or be specific, like if(ch->ispet, mount, whatever) if (!ch->IsPC() && !ch->IsGoto() && !ch->IsWarp() && !ch->IsDoor()) SECTREE_MANAGER::Instance().ExtendPreloadedEntitiesMap(lMapIndex, pkMob->m_table.dwVnum); #endif
  19. [Hidden Content] [Hidden Content]
  20. Hello, As you may already be aware, the official source code that was leaked some time ago includes code for saving window status. The code is designed to save various window attributes such as visibility, minimized status, x and y coordinates, and height. However, I have made some adjustments to only save the x and y coordinates. Please note that the logic I have utilized is different from the original planned approach. In order to ensure the proper functioning of the save function, it is imperative to address an issue where the function is called too late and the interfacehandler is null: ## 1. Open UserInterface/PythonSystem.cpp ## 1. Replace the following function: void CPythonSystem::SaveInterfaceStatus() { ... } ## 1. With: void CPythonSystem::SaveInterfaceStatus() { if(m_poInterfaceHandler) // This will always be null when this function is called PyCallClassMemberFunc(m_poInterfaceHandler, "OnSaveInterfaceStatus", Py_BuildValue("()")); FILE* File; File = fopen("interface.cfg", "wb"); if(!File) { TraceError("Cannot open interface.cfg"); return; } fwrite(m_WindowStatus, 1, sizeof(TWindowStatus) * WINDOW_MAX_NUM, File); fclose(File); } Now, let's explore how we can save window attributes, specifically for the inventory window as an example: ## 1. Go to interfaceModule.py: ## 1. Search: if self.wndInventory: self.wndInventory.Hide() self.wndInventory.Destroy() ## 1. Change it like this: if self.wndInventory: xInventory, yInventory = self.wndInventory.GetGlobalPosition() systemSetting.SaveWindowStatus(systemSetting.WINDOW_INVENTORY, False, True, xInventory, yInventory, 0) self.wndInventory.Hide() self.wndInventory.Destroy() ## 2. Now search: self.wndInventory = uiInventory.InventoryWindow() self.wndInventory.BindInterfaceClass(self) ## 2. Change it like this: self.wndInventory = uiInventory.InventoryWindow() self.wndInventory.BindInterfaceClass(self) (_, _, invX, invY, _) = systemSetting.GetWindowStatus(systemSetting.WINDOW_INVENTORY) if invX > 0 and invY > 0 and invX + self.wndInventory.GetWidth() < wndMgr.GetScreenWidth() and invY + self.wndInventory.GetHeight() < wndMgr.GetScreenHeight(): self.wndInventory.SetPosition(invX, invY) I hope you find this information useful.
  21. [Hidden Content] [Hidden Content] Reversed from 22.2.7.0 Official Binary. Client part is from 2018 Official Root.
  22. Before: After: Version with Tabs: PasteBin or M2Bin uitooltip.py Find def AppendTextLine(self, text, color = FONT_COLOR, centerAlign = True): Delete or comment this if not self.CanEquip() and self.bCannotUseItemForceSetDisableColor: color = self.DISABLE_COLOR Find def __SetNormalItemTitle(self): Before add def __CheckAntiFlag(self): race = player.GetRace() job = chr.RaceToJob(race) if item.IsAntiFlag(self.ANTI_FLAG_DICT[job]): return True else: return False def __CheckSex(self): sex = chr.RaceToSex(player.GetRace()) MALE = 1 FEMALE = 0 if item.IsAntiFlag(item.ITEM_ANTIFLAG_MALE) and sex == MALE: return True if item.IsAntiFlag(item.ITEM_ANTIFLAG_FEMALE) and sex == MALE: return False Find and replace def __SetNormalItemTitle(self): and def __SetSpecialItemTitle(self): with def __SetNormalItemTitle(self): if self.__CheckAntiFlag() == True: self.AppendTextLine(item.GetItemName(), self.DISABLE_COLOR) else: if self.__CheckSex() == True: self.AppendTextLine(item.GetItemName(), self.DISABLE_COLOR) else: self.AppendTextLine(item.GetItemName(), self.TITLE_COLOR) def __SetSpecialItemTitle(self): if self.__CheckAntiFlag() == True: self.AppendTextLine(item.GetItemName(), self.DISABLE_COLOR) else: if self.__CheckSex() == True: self.AppendTextLine(item.GetItemName(), self.DISABLE_COLOR) else: self.AppendTextLine(item.GetItemName(), self.SPECIAL_TITLE_COLOR) Find and replace def AppendWearableInformation(self): with def AppendWearableInformation(self): self.AppendSpace(5) if self.__CheckAntiFlag() == True: self.AppendTextLine(localeInfo.TOOLTIP_ITEM_WEARABLE_JOB, self.DISABLE_COLOR) else: self.AppendTextLine(localeInfo.TOOLTIP_ITEM_WEARABLE_JOB, self.NORMAL_COLOR) flagList = ( not item.IsAntiFlag(item.ITEM_ANTIFLAG_WARRIOR), not item.IsAntiFlag(item.ITEM_ANTIFLAG_ASSASSIN), not item.IsAntiFlag(item.ITEM_ANTIFLAG_SURA), not item.IsAntiFlag(item.ITEM_ANTIFLAG_SHAMAN)) characterNames = "" for i in xrange(self.CHARACTER_COUNT): name = self.CHARACTER_NAMES[i] flag = flagList[i] if flag: characterNames += " " characterNames += name if self.__CheckAntiFlag() == True: textLine = self.AppendTextLine(characterNames, self.DISABLE_COLOR, True) else: textLine = self.AppendTextLine(characterNames, self.NORMAL_COLOR, True) textLine.SetFeather() race = player.GetRace() sex = chr.RaceToSex(race) MALE = 1 FEMALE = 0 if item.IsAntiFlag(item.ITEM_ANTIFLAG_MALE): if sex == MALE: textLine = self.AppendTextLine(localeInfo.FOR_FEMALE, self.DISABLE_COLOR, True) textLine.SetFeather() else: textLine = self.AppendTextLine(localeInfo.FOR_FEMALE, self.NORMAL_COLOR, True) textLine.SetFeather() if item.IsAntiFlag(item.ITEM_ANTIFLAG_FEMALE): if sex == FEMALE: textLine = self.AppendTextLine(localeInfo.FOR_MALE, self.DISABLE_COLOR, True) textLine.SetFeather() else: textLine = self.AppendTextLine(localeInfo.FOR_MALE, self.NORMAL_COLOR, True) textLine.SetFeather() With help of chatgpt i made better version: [Hidden Content]
  23. M2 Download Center Download Here ( Internal ) [Hidden Content] The client part is from 2018 official root. Includes net.SendItemCombinationPacketCancel(), which was added later. Don't forget to add the slot marking.
  24. Hey, Today i will make a small guide how to enable refinement scroll to be stackable. This will enable you to stack any refinement scroll such as blessing scroll, magic metal etc. Before we start diving into the source code, make sure to look into item_proto and check that there isn't any ANTI_STACK flag and the item is defined as ITEM_STACKABLE. Client side: Open uiinventory.py Search for: def __DropSrcItemToDestItemInInventory(self, srcItemVID, srcItemSlotPos, dstItemSlotPos): if srcItemSlotPos == dstItemSlotPos: return if item.IsRefineScroll(srcItemVID): Replace with: def __DropSrcItemToDestItemInInventory(self, srcItemVID, srcItemSlotPos, dstItemSlotPos): if srcItemSlotPos == dstItemSlotPos: return if item.IsRefineScroll(srcItemVID): if player.GetItemIndex(srcItemSlotPos) == player.GetItemIndex(dstItemSlotPos): self.__SendMoveItemPacket(srcItemSlotPos, dstItemSlotPos,0) else: self.RefineItem(srcItemSlotPos, dstItemSlotPos) self.wndItem.SetUseMode(FALSE) Search for: if item.IsRefineScroll(srcItemVNum): if player.REFINE_OK == player.CanRefine(srcItemVNum, dstSlotPos) Replace with: if item.IsRefineScroll(srcItemVNum): if player.REFINE_OK == player.CanRefine(srcItemVNum, dstSlotPos) or player.GetItemIndex(dstSlotPos) == srcItemVNum: That's all, Enjoy!
×
×
  • 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.