Jump to content

metin2-factory

Inactive Member
  • Posts

    174
  • Joined

  • Last visited

  • Days Won

    13
  • Feedback

    0%

Posts posted by metin2-factory

  1. 4 hours ago, metin2team said:

    why do you use server-side while you can do it only using client-side?

    At first i tried only client side but there were 2 down sides. first, the flags are declared only in server side that means you'd have to add a new enum in

    client side which is pointless. and second, for some reason a few raceflag do not show properly on client side. also, i prefer the logic to remain in server side.

    It doesn't matter much and i rather keep the code clean and easier to work with. also, server side check is required for the element icon over player target which ill add later on.

    • Love 1
  2. Small update:

    Added tool tip to make it more clear for players, follow the steps below to have it.

    Like this post if you find it useful :)

    Screens:

    t0QauxcjSpaHB3IpWxtP_A.png 

    Lu5jH5K9QTarD5hh0uaVeQ.png

     

    in _init_ and in Destroy methods look for:

    if app.ENABLE_VIEW_ELEMENT:
    	self.elementImage = None

    replace with:

    if app.ENABLE_VIEW_ELEMENT:
    	self.elementImage = None
    	self.elementId = None
    	self.elementImageToolTip = None

    search for:

    def Close(self):

    add inside the method:

    if app.ENABLE_VIEW_ELEMENT and self.elementImage:
    	self.elementImage.Hide()

     

    Search for:

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

    add above:

    import uiToolTip

    inside ResetTargetBoard method look for:

    if app.ENABLE_VIEW_ELEMENT and self.elementImage:
    	self.elementImage = None

    replace with:

    if app.ENABLE_VIEW_ELEMENT and self.elementImage:
      self.elementImage = None
      self.elementId = None
      if self.elementImageToolTip:
      self.elementImageToolTip.Hide()

    Look for:

    def SetElementImage(self, elementId):

    replace the whole method with:

    		def SetElementImage(self, elementId):
    			try:
    				if elementId > 0 and elementId in ELEMENT_IMAGE_DIC.keys():
    					self.elementId = elementId
    					self.elementImage = ui.ImageBox()
    					self.elementImage.SAFE_SetStringEvent("MOUSE_OVER_IN", self.OnElementImageOverIn)
    					self.elementImage.SAFE_SetStringEvent("MOUSE_OVER_OUT", self.OnElementImageOverOut)
    					self.elementImage.SetPosition(self.GetLeft() - 40, self.GetTop())
    					self.elementImage.LoadImage(
    						"d:/ymir work/ui/game/12zi/element/%s.sub" % (ELEMENT_IMAGE_DIC[elementId]))
    					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(self.GetLeft() - 40, self.GetTop() + 70)
    			self.elementImageToolTip.Show()
    
    		def OnElementImageOverOut(self):
    			if self.elementImageToolTip:
    				self.elementImageToolTip.Hide()

    That's it.

    Enjoy!

    • Metin2 Dev 2
    • Love 6
  3. 19 minutes ago, Sonitex said:

    That's the worst part, there is no errors... 

    use sys_err function server side(char.cpp) and print in python(game.py) to find bElement value. 

    it should be between 1 and 6 for elemental mobs. if it's not in this range then you did something wrong.

     

    Also, make sure in mob_proto server side the mobs race is with ATT_
    for example: ATT_ICE, ATT_FIRE, ATT_WIND etc etc

    • Love 3
  4. 2 hours ago, Horinna said:
    
    PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetHPTargetBoard", Py_BuildValue("(iiiii)", TargetPacket.dwVID, TargetPacket.bHPPercent, TargetPacket.bElement));

    to

     

    
    PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetHPTargetBoard", Py_BuildValue("(iii)", TargetPacket.dwVID, TargetPacket.bHPPercent, TargetPacket.bElement));

    Thanks, i'v updated my post.
    If you have the error below:
     

    1028 16:37:29247 :: TypeError
    1028 16:37:29247 :: : 
    1028 16:37:29247 :: SetHPTargetBoard() takes exactly 4 arguments (6 given)
    1028 16:37:29247 :: 


    open PythonNetworkPhaseGame and modify as above

  5. M2 Download Center

    This is the hidden content, please
    ( Internal )

    Hey there,

    I have an Halloween gift for you all. i have been working for a few hours on official like element image on target window(See screenshots below).

    When you click on a mob if it is defined as elemental, it will open an element image in addition to the target window.

    Don't forget to hit the like button! ;)

    (C) Metin2 guild wars - coded by [GA]Ruin - 27/10/2017 (I create custom metin2 systems in c++/python. if you want a custom system send me a pm and we can talk over skype).


    Let's begin! 


    Server Side:

    Open service.h, add in the end:

    #define ELEMENT_TARGET

     

    Open char.cpp, search for

    else
    	{
    		p.dwVID = 0;
    		p.bHPPercent = 0;
    }

     

    add below:

    #ifdef ELEMENT_TARGET
    	const int ELEMENT_BASE = 11;
    	DWORD curElementBase = ELEMENT_BASE;
    	DWORD raceFlag;
    	if (m_pkChrTarget && m_pkChrTarget->IsMonster() && (raceFlag = m_pkChrTarget->GetMobTable().dwRaceFlag) >= RACE_FLAG_ATT_ELEC)
    	{
    		for (int i = RACE_FLAG_ATT_ELEC; i <= RACE_FLAG_ATT_DARK; i *= 2)
    		{
    			curElementBase++;
    			int diff = raceFlag - i;
    			if (abs(diff) <= 1024)
    				break;
    		}
    		p.bElement = curElementBase - ELEMENT_BASE;
    	}
    	else
    	{
    		p.bElement = 0;
    	}
    
    #endif

     

    open packet.h, search for:

    } TPacketGCTarget;

    add above:

    #ifdef ELEMENT_TARGET
    	BYTE	bElement;
    #endif

     

    Client side:

    open locale_inc.h, add in the end:

    #define ELEMENT_TARGET

    open packet.h, search for 

    } TPacketGCTarget;

    add above:

    #ifdef ELEMENT_TARGET
    	BYTE bElement;
    #endif

    open PythonNetworkPhaseGame.cpp, look for:

    else if (pInstPlayer->CanViewTargetHP(*pInstTarget))

    replace below with the following:

    #ifdef ELEMENT_TARGET
    				PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetHPTargetBoard", Py_BuildValue("(iii)", TargetPacket.dwVID, TargetPacket.bHPPercent, TargetPacket.bElement));
    #else
    
    				PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "SetHPTargetBoard", Py_BuildValue("(ii)", TargetPacket.dwVID, TargetPacket.bHPPercent));
    #endif

    open PythonApplicationModule.cpp, look for 

    #ifdef ENABLE_ENERGY_SYSTEM

    add above:

    #ifdef ELEMENT_TARGET
    	PyModule_AddIntConstant(poModule, "ENABLE_VIEW_ELEMENT", 1);
    #else
    	PyModule_AddIntConstant(poModule, "ENABLE_VIEW_ELEMENT", 0);
    #endif

    open game.py, look for 

    def SetHPTargetBoard(self, vid, hpPercentage):
    			if vid != self.targetBoard.GetTargetVID():
    				self.targetBoard.ResetTargetBoard()
    				self.targetBoard.SetEnemyVID(vid)
    
    			self.targetBoard.SetHP(hpPercentage)
    			self.targetBoard.Show()

    replace with:

    if app.ENABLE_VIEW_ELEMENT:
    		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()

    open uitarget.py, look for 

    import background

    add below:

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

    look for:

    self.isShowButton = False

    add below:

    if app.ENABLE_VIEW_ELEMENT:
    			self.elementImage = None

    inside Destroy method, look for:

    self.__Initialize()

    add below:

    if app.ENABLE_VIEW_ELEMENT:
    			self.elementImage = None

    inside ResetTargetBoard method, look for:

    self.hpGauge.Hide()

    add below:

    if app.ENABLE_VIEW_ELEMENT and self.elementImage:
    			self.elementImage = None

    look for :

    def SetElementImage(self,elementId):

    add above:

    if app.ENABLE_VIEW_ELEMENT:
    		def SetElementImage(self,elementId):
    			try:
    				if elementId > 0 and elementId in ELEMENT_IMAGE_DIC.keys():
    					self.elementImage = ui.ImageBox()
    					self.elementImage.SetParent(self.name)
    					self.elementImage.SetPosition(-60,-12)
    					self.elementImage.LoadImage("d:/ymir work/ui/game/12zi/element/%s.sub" % (ELEMENT_IMAGE_DIC[elementId]))
    					self.elementImage.Show()
    			except:
    				pass

     

    Compile server, client source and root pack and that's it!

     

    Enjoy!

    Happy halloween! :)

    • Metin2 Dev 112
    • Eyes 1
    • Dislove 3
    • Angry 1
    • Think 2
    • Confused 6
    • Lmao 2
    • Good 27
    • Love 6
    • Love 180
  6. 8 hours ago, Tasho said:

    Maybe he was want to do something with the sum.

    Should look like that:

      Hide contents
    
    
    //PythonChat.h
    BOOL GetChatMode(DWORD dwID);
    
    //PythonChat.cpp
    BOOL CPythonChat::GetChatMode(DWORD dwID)
    {
    	TChatSet * pChatSet = GetChatSetPtr(dwID);
    	if (!pChatSet)
    		return FALSE;
    
    	BYTE byChatHistoryLogModes[] = {
    		CHAT_TYPE_TALKING, CHAT_TYPE_INFO, CHAT_TYPE_NOTICE, CHAT_TYPE_PARTY, CHAT_TYPE_GUILD, CHAT_TYPE_SHOUT,
    		#ifdef ENABLE_DICE_SYSTEM
    		CHAT_TYPE_DICE_INFO
    		#endif
    	};
    
    	int iRet = 0;
    	for (BYTE i = 0; i < _countof(byChatHistoryLogModes); i++)
    	{
    		if (pChatSet->CheckMode(byChatHistoryLogModes[i]))
    			iRet += 1 << byChatHistoryLogModes[i];
    	}
    
    	return iRet > 0;
    }
    
    //PythonChatModule.cpp
    PyObject * chatGetChatMode(PyObject* poSelf, PyObject* poArgs)
    {
    	int iID;
    	if (!PyTuple_GetInteger(poArgs, 0, &iID))
    		return Py_BuildException();
    
    	return Py_BuildValue("b", CPythonChat::Instance().GetChatMode(iID));
    }
    
    //Python
    	def ToggleChatMode(self, mode):
    		if self.allChatMode:
    			self.allChatMode = False
    
    			for i in self.CHAT_MODE_INDEX:
    				chat.DisableChatMode(self.chatID, i)
    
    			chat.EnableChatMode(self.chatID, mode)
    			self.btnAll.SetUp()
    		else:
    			chat.ToggleChatMode(self.chatID, mode)
    
    			if not chat.GetChatMode(self.chatID):
    				self.btnAll.Down()
    				self.ToggleAllChatMode()

     

     

    well, since iRet is just for debug, this will be better.

     

    BOOL CPythonChat::IsChatModeEnabled(DWORD dwID)
    {
    	TChatSet * pChatSet = GetChatSetPtr(dwID);
    	if (!pChatSet)
    		return FALSE;
    
    	for (BYTE i = 0; i < CHAT_TYPE_MAX_NUM; i++)
    	{
    		if (pChatSet->CheckMode(i))
    			return TRUE;
    	}
    	return FALSE;
    }
    isModeEnabled = chat.IsChatModeEnabled(self.chatID)
    if not isModeEnabled:
    	self.btnAll.Down()
    	self.ToggleAllChatMode()

     

     

    But anyway, it's not a big deal. everyone has its own style :P

  7. Every time you're using direct query it allocates new object of SQLMSg and it returns the pointer to this object.

    it'd be preffered to be handled by an auto_ptr so it would deallocate all of the containing dynamic objects inside of SQLMsg automatically when SQLMsg destructor is called.

    The reason they used a delete in this call is because they probably knew for certian they wouldn't use this pointer to the object anymore and it can potentially cause a memory leak.

    My advice is to always use an auto_ptr as it saves you the trouble to remember where and when to delete this pointer.

    *Incase you know for sure that you won't use the SQLMsg pointer object anymore(mostly for actions such as UPDATE / DELETE / INSERT) then you should add delete before the directquery as you mentioned above(Although, you are still in risk that the dynamically allocated objects inside SQLMsg will not be free'd).

    Hope i made it clear.

    • Love 2
  8. 19 minutes ago, StormHunter said:

    Im a leecher dumbass for saying the truth?

    If it makes you have to claim stuff you didnt made, poor you.

    Mate, So far i'm the one with 100+ rank/likes. i have contributed to this forum much more than you that's for sure.

    Surf around the C++ code release section and find for yourself how many useful guides i made. all of my stuff worked and working today 100%.

    I have never posted any leeched code/tool and i have no intention to do so. 

    So take your lame ass some where else/keep your thoughts to yourself.

    Thanks.

    P.S Here's a proof for the efficient difference between my tool and the old italian tool.

    If you have a little bit of programming knowledge you'll easily realize which one is better.

    My code:

    1qeyaRDnT32oTJSBde9r1Q.png

     

    Italian tool code:

     

    rJSzyKEeRfSaIdgxYHc1Cg.png

     

     

     

     

     

  9. 12 hours ago, StormHunter said:

    You worked on it during the past week? Did you?

    Or did you just change some buttons placement and branded it as your own?

     

    WPF? Could swear its winforms.

    P.S: Obfuscating it doesnt change the fact you used an already available free code, changed partially its visual appearance and branded it your own. At least show respect and credit the first releaser.

    What a load of crap. there is a similar tool made long time ago(in Italian language) but i took nothing out of this tool code except a few layout design ideas. the italian tool is poorly coded with unefficient & un-maintainable code, without seperation of UI and Logic,No containers, and the list goes on and on. 

    Here, i have made it fully english + coded the tool from scratch(in an efficient,maintainable way) +  coded new features that no tool existing today has. and i have obfuscated it so leecher dumbass like yourself can't steal the code.

    You don't have to trust me but it's a fact that this tool has features that no other tool has today.

    And yes, the tool was built with wpf.

     

    P.S

    Quote
    • mob/group file viewer. 
    • Importing regen file.
    • Remember information - Remember the last data entered such as direction, respawn time,count etc.
    • Color Character by color(Mob-Red, Stone-Blue, Boss-turquoise, NPC-Belge, Group-Black).
    • Add a character - Left click.
    • Remove a character - right click on a character dot.
    • Load MOB/Group information - select mob_names.txt/group.txt to view information on a data grid(shown on screen shots below). When choosing a group.txt make sure you have type field set on group.
    • Ctrl Z Feature - Reverse action, that means that if you added a character it will be deleted and if you removed a character it will be added back.
    • Separation of exported files - Files will be exported upon the type of the map character, if you had stone,boss and npc character then stone.txt,boss.txt and npc.txt will be generated.

    About 90% of these features do not exist in the old italian tool.

    • kekw 1
  10. M2 Download Center

    This is the hidden content, please
    ( Internal )

    Spoiler

    0829492OJq6pg.gif
    0829499t8edIL.gif

     

    Advanced Regen Editor

    I have worked in the past week on a new regen tool(made in C#-WPF) to make the life easier for the mappers/server owner between us.

    It is an advanced regen tool that includes all the basic functions + new ones such as:

    • mob/group file viewer. 
    • Importing regen file.
    • Remember information - Remember the last data entered such as direction, respawn time,count etc.
    • Color Character by color(Mob-Red, Stone-Blue, Boss-turquoise, NPC-Belge, Group-Black).
    • Add a character - Left click.
    • Remove a character - right click on a character dot.
    • Load MOB/Group information - select mob_names.txt/group.txt to view information on a data grid(shown on screen shots below). When choosing a group.txt make sure you have type field set on group.
    • Ctrl Z Feature - Reverse action, that means that if you added a character it will be deleted and if you removed a character it will be added back.
    • Separation of exported files - Files will be exported upon the type of the map character, if you had stone,boss and npc character then stone.txt,boss.txt and npc.txt will be generated.

    If you find any bugs, please reply here with the bug information in specific details.

    Please Like this thread if you find my tool useful! :)

     

     Metin2 Guild Wars.

    Version 1.0 Download Link:   

    This is the hidden content, please

    Update 06/10/2017:

    • Zoom in/out feature has been added.
    • View entities seperately feature has been added.
    • Import regen bug has been fixed.
    • Enjoy!

     

     

     

    Version 1.1 Download Link:  

    This is the hidden content, please

    Virustotal: 

    This is the hidden content, please

     

    Enjoy!!

    • Metin2 Dev 220
    • Dislove 4
    • Sad 2
    • Cry 1
    • Think 5
    • Confused 1
    • Lmao 1
    • Good 59
    • Love 15
    • Love 141
  11. 8 hours ago, Rachx3 said:

     

    :unsure:

    Well, i didn't see someone published it before until now. 

    and if you look at the implementations of his and mine, you could easily notice the difference.

    Anyway, it doesn't hurt :)

  12. 4 hours ago, Galet said:

    Thanks ! I remember this feature was a part of samouraï core, but I'm unsure, by the way, thanks !

    This feature was created custom made by me. but a similar version may be included in other servers.

    and np :)

     

    Quote

    Do you have a feature to reload the  item\mob proto?
    With "/reload p" nothing happens

     

    It should work, you have an issue with your server files/src.

    I can help you and fix it(not for free), send me a pm.

  13. M2 Download Center

    This is the hidden content, please
    ( Internal )

    Author: (c) Metin2 Factory/Guild Wars

    This implementation includes a new ingame GM command:

    /reload_regen which reloads ingame current map regen(regen.txt,boss.txt,stones.txt,etc) including server_attr

     

    Please follow the following steps:

    Open cmd.cpp

    look for:
    ACMD(do_purge);
     

    Add below:

    ACMD(reload_regen);

     

    Look for:
    { "nowar",        do_nowar,        0,            POS_DEAD,    GM_PLAYER    },

    Add below:
     

    { "reload_regen", reload_regen ,    0,        POS_DEAD,    GM_GOD        },

     

    Open cmd_gm.cpp

     

    look for the end of ACMD(do_purge) function

    and add below:

     

    ACMD(reload_regen)
    {
        std::vector<LPEVENT> regenEvent = SECTREE_MANAGER::instance().GetRegenEvent(ch->GetMapIndex());
        for (std::vector<LPEVENT>::iterator it = regenEvent.begin(); it != regenEvent.end(); ++it)
        {
            event_cancel(&(*it));
        }
        FuncPurge func(ch);
        func.m_bAll = true;
        LPSECTREE_MAP lm = SECTREE_MANAGER::instance().GetMap(ch->GetMapIndex());
        lm->for_each(func);
        char * mapIndex;
        mapIndex = number_to_str(ch->GetMapIndex(), 10);
        SECTREE_MANAGER::instance().BuildMap(mapIndex, LocaleService_GetMapPath().c_str());
    }

     

    Open sectree_manager.cpp

    Look for the end of int SECTREE_MANAGER::Build(const char * c_pszListFileName, const char* c_pszMapBasePath) function

    Add below:
     

    int SECTREE_MANAGER::BuildMap(const char * c_pszMapID, const char* c_pszMapBasePath)
    {
        
        std::string mapIndexPath = c_pszMapBasePath;
        mapIndexPath += "/index";
        int test;
        FILE* fp = fopen(mapIndexPath.c_str(), "rb");
        if (fp == NULL)
        {
            return 0;
        }
        std::string line;
        char buf[256 + 1];
        while (fgets(buf, 256, fp))
        {
            std::string tmp = buf;
            if (tmp.find(c_pszMapID) != std::string::npos)
            {
                printf("found!!");
                break;
            }
            
        }
    
        char szFilename[256];
        char szMapName[256];
        int iIndex;
    
        *strrchr(buf, '\n') = '\0';
    
        if (!strncmp(buf, "//", 2) || *buf == '#')
            return 0;
    
        sscanf(buf, " %d %s ", &iIndex, szMapName);
    
        snprintf(szFilename, sizeof(szFilename), "%s/%s/Setting.txt", c_pszMapBasePath, szMapName);
    
        TMapSetting setting;
        setting.iIndex = iIndex;
    
            if (!LoadSettingFile(iIndex, szFilename, setting))
            {
                sys_err("can't load file %s in LoadSettingFile", szFilename);
                return 0;
            }
    
            snprintf(szFilename, sizeof(szFilename), "%s/%s/Town.txt", c_pszMapBasePath, szMapName);
    
            if (!LoadMapRegion(szFilename, setting, szMapName))
            {
                sys_err("can't load file %s in LoadMapRegion", szFilename);
                return 0;
            }
    
            if (true == test_server)
                sys_log(0, "[BUILD] Build %s %s %d ", c_pszMapBasePath, szMapName, iIndex);
    
            // ¸ÕÀú ÀÌ ¼­¹ö¿¡¼­ ÀÌ ¸ÊÀÇ ¸ó½ºÅ͸¦ ½ºÆùÇØ¾ß Çϴ°¡ È®ÀÎ ÇÑ´Ù.
            if (map_allow_find(iIndex))
            {
                LPSECTREE_MAP pkMapSectree = BuildSectreeFromSetting(setting);
                m_map_pkSectree.insert(std::map<DWORD, LPSECTREE_MAP>::value_type(iIndex, pkMapSectree));
    
                snprintf(szFilename, sizeof(szFilename), "%s/%s/server_attr", c_pszMapBasePath, szMapName);
                LoadAttribute(pkMapSectree, szFilename, setting);
    
                snprintf(szFilename, sizeof(szFilename), "%s/%s/regen.txt", c_pszMapBasePath, szMapName);
                regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY);
    
                snprintf(szFilename, sizeof(szFilename), "%s/%s/npc.txt", c_pszMapBasePath, szMapName);
                regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY);
    
                snprintf(szFilename, sizeof(szFilename), "%s/%s/boss.txt", c_pszMapBasePath, szMapName);
                regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY);
    
                snprintf(szFilename, sizeof(szFilename), "%s/%s/stone.txt", c_pszMapBasePath, szMapName);
                regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY);
    
                snprintf(szFilename, sizeof(szFilename), "%s/%s/dungeon.txt", c_pszMapBasePath, szMapName);
                LoadDungeon(iIndex, szFilename);
    
                pkMapSectree->Build();
            }
        return 1;
    }

    Open regen.cpp

    Look for:
    regen->event = event_create(regen_event, info, PASSES_PER_SEC(number(0, 16)) + PASSES_PER_SEC(regen->time)); 

    add below:
     

    SECTREE_MANAGER::instance().AddRegenEventToMap(lMapIndex, regen->event);

    Open sectree_manager.h
    Look for:
    std::map<DWORD, std::vector<npc_info> > m_mapNPCPosition;
    Add below:
     

    std::map<long, std::vector<LPEVENT>> m_mapRegen;

    Look for:
    bool        GetRandomLocation(long lMapIndex, PIXEL_POSITION & r_pos, DWORD dwCurrentX = 0, DWORD dwCurrentY = 0, int iMaxDistance = 0);

    Add below:

    void		AddRegenEventToMap(long lMapIndex, LPEVENT event) { m_mapRegen[lMapIndex].push_back(event); }
    		std::vector<LPEVENT>		GetRegenEvent(long lMapIndex) { return m_mapRegen[lMapIndex]; }

     

    Open utils.h from common folder
    Look for:
    /*----atoi function-----*/

    Add below:
     

    /*----itoa function-----*/
    
    inline char* number_to_str(int val, int base)
    {
    	static char buf[32] = { 0 };
    
    	int i = 30;
    
    	for (; val && i; --i, val /= base)
    
    		buf[i] = "0123456789abcdef"[val % base];
    
    	return &buf[i + 1];
    
    }
    
    /*----itoa function-----*/

     

    Recompile the source and enjoy.

    • Metin2 Dev 8
    • Good 4
    • Love 10
  14. Look at the client/server source code. learn the classes/functions hierarchy. Add/Modify slowly the source and experience the changes in game.

    Learn the Client/Server packet structure and try adding your own packets to transmit data from client to server and vice versa.

    Take a look at some released systems from known people and study what they did.

    GL.

    • Love 1
  15. 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.

     

     

    224736d21caa65b1d041acba5dd0389e20c3ec.p

    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!

    • Metin2 Dev 1
    • Good 1
    • Love 6
  16. Hey,

    I have made a small function that will enable you to use an unlimited amount of arguments in server source code.

    For example look at the function do_item in cmd_gm.cpp, it gets 2 arguments : arg1 and arg2.

    Using my function you will be able to have as many arguments easier and in more convenient way. 

    That means you can have 5,7 or even 20 arguments.

    Let's begin:

    Open utils.cpp and look for #include "stdafx.h" add below the following:

     

    #include <boost/algorithm/string/classification.hpp> // Include boost::for is_any_of
    #include <boost/algorithm/string/split.hpp>

     

    look for  const char *first_cmd

    add above:

    void split_argument(const char *argument, std::vector<std::string> & vecArgs)
    {
    	std::string arg = argument;
    	boost::split(vecArgs, arg, boost::is_any_of(" "), boost::token_compress_on);
    }

    open utils.h and look for const char * first_cmd

    add above:

    extern void split_argument(const char *argument, std::vector<std::string> & vecArgs);

    That's all.

    How to use?

    Let's look for example in ACMD(do_item) method:

    Instead of

    char arg1[256], arg2[256];
    
    two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));

    you can replace with:

    std::vector<std::string> vecArgs;
    split_argument(argument,vecArgs);

    And now you can access any of the arguments starting from index of 1.

    so for example if you type ingame the command /item 6001 10

    vecArgs[1] is 6001 

    vecArgs[2] is 10

    if you need to convert it to number, you can use as example:

    int iCount = 0;
    
    str_to_number(iCount, vecArgs[2].c_str());

     

    If you need any assistance, write here a reply and ill do my best in helping you.

    Enjoy :)

    • Love 10
×
×
  • 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.