Jump to content

Ikarus_

Developer
  • Posts

    402
  • Joined

  • Last visited

  • Days Won

    20
  • Feedback

    0%

Posts posted by Ikarus_

  1. It looks like it is getting "false" as an int somehow. I ve no idea why it is happening only to you.

    A dirty solution may be define a spaceship operator with bool and int at the beginning of AsyncSQL.h (before the includes).

    Since i can't reproduce the error i m not able to check if my propose is valid (and i neither tried to compile the code tbh).

     

    inline constexpr auto operator<=>(const bool x, const int y)
    {
    	return x <=> bool(y);
    }

     

     

     

    252709OrangeWarning.pngto be honest i don't like it, i hate it, and i ve many doubts that it will work.

     

    Another ugly way would be to use bool(false) instead of false where is getting the error.... but i don't really like to modify std files..

     

     

    A test that i think i may try to suggest you use to move the standard files included in AsyncSQL.h to the beginning of the file (move them above the other includes, i ve seen your files in stackoverflow question you made)

     

     

    EDIT:

    I ve found the cause of the error, it is a macro in libthrecore/stdafx.h and following my suggestion of move up the standard headers and move down the user defined headers you will solve your error.

     

    here the macro is destroying the standard code:

    
    #ifndef false
    #define false	0
    #define true	(!false)
    #endif

     

    • Love 1
  2. On 3/13/2021 at 11:28 AM, astroNOT said:

    Hello,

     

    How can i create a new button that will show somewhere on the player's screen, which files stand for button object creation, and which module is the actual UI design ? To respect the patterns already implemented?

     

    I assume I would create a button based on the classes in ui.py module. The question is where do I create the actual UI definition to display the button

     

    in game? And on click, the lets say icon.tga button would display a message, "Hello world"?

     

    Thanks

    It depend where you need to add it... 

    e.g.
    add button in inventory -> uiinventory.py
    add button in taskbar -> uitaskbar.py

    add button in minimap -> uiminimap.py

    etc etc

  3. ScriptWindow (as the name suggests) are window created using scriptfiles (you can find a lot of them in uiscript and in locale/xx/ui).

    These script files are (in short) a dictionary of items with settings of certain keys used by PythonScriptLoader class to assign to the elements the properties linked with the keys.

     

    Let's show here an example:
     

    Spoiler

    File uiscript/inputdialog.py

     

    
    
    
    
    
    
    
    
    
    import uiScriptLocale
    
    window = {
    	"name" : "InputDialog",
    
    	"x" : 0,
    	"y" : 0,
    
    	"style" : ("movable", "float",),
    
    	"width" : 170,
    	"height" : 90,
    
    	"children" :
    	(
    		{
    			"name" : "Board",
    			"type" : "board_with_titlebar",
    
    			"x" : 0,
    			"y" : 0,
    
    			"width" : 170,
    			"height" : 90,
    
    			"title" : "",
    
    			"children" :
    			(
    
    				## Input Slot
    				{
    					"name" : "InputSlot",
    					"type" : "slotbar",
    
    					"x" : 0,
    					"y" : 34,
    					"width" : 90,
    					"height" : 18,
    					"horizontal_align" : "center",
    
    					#"type" : "image",
    					#"image" : "d:/ymir work/ui/public/Parameter_Slot_03.sub",
    
    					"children" :
    					(
    						{
    							"name" : "InputValue",
    							"type" : "editline",
    
    							"x" : 3,
    							"y" : 3,
    
    							"width" : 90,
    							"height" : 18,
    
    							"input_limit" : 12,
    						},
    					),
    				},
    
    				## Button
    				{
    					"name" : "AcceptButton",
    					"type" : "button",
    
    					"x" : - 61 - 5 + 30,
    					"y" : 58,
    					"horizontal_align" : "center",
    
    					"text" : uiScriptLocale.OK,
    
    					"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
    					"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
    					"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
    				},
    				{
    					"name" : "CancelButton",
    					"type" : "button",
    
    					"x" : 5 + 30,
    					"y" : 58,
    					"horizontal_align" : "center",
    
    					"text" : uiScriptLocale.CANCEL,
    
    					"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
    					"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
    					"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
    				},
    			),
    		},
    	),
    }

     

     

    All the scripts have local variable named window (the dictionary that contains all the settings).

    The first dictionary's (window) keys describe the scriptwindow properties, the window name, the height/width, the x/y where the window spawn, the style of the window (in this case moveable mean the window can be moved with the mouse and float mean the window has an order how the children are show and they can be moved over other children using SetTop).

     

    the window usually has a "children" key that describe a tuple of dictionaries.

    The tuple start with "(" and end with ")," and it contains other dictionaries that describe the children properties.

     

    and example is the "Board" child that is a "board_with_titlebar" element (so a board with a titlebar and a close button on the top side).

    the "type" key is really important, it describe what kind of element is going to be create. You can read all types available and all keys you can use to assign properties to the elements in the class PythonScriptLoader (especially in def LoadChildren) in ui.py.

     

    The self.GetChild you mentioned is used to obtain the element using its "name" property.

    The script window are a really clever way to make a window, but it has some limit.

    The window made by using the script window can contain in the script only the "static" elements, the elements that are always created with the board.

    To create dynamically the elements you have to code them and to assign the properties using the class methods defined in ui.py

    An example on how you can create a button would be:
     

    import ui
    ...
    ...
    ...
    
    class MyBoardExample(ui.Window):
      ...
      ...
      ...
      ...
      
      
      def LoadDynamicElements(self):
        race = player.GetRace()
        race_image_default = "d:/ymir work/ui/game/race_%d_default.sub"%race
        race_image_down = "d:/ymir work/ui/game/race_%d_down.sub"%race
        race_image_over = "d:/ymir work/ui/game/race_%d_over.sub"%race
        
        self.MainCharRaceButton = ui.Button()
        self.MainCharRaceButton.SetParent(self) #giving the parent to link the button the main board
        self.MainCharRaceButton.SetPosition(105, 456) #giving position using local coordinates
        self.MainCharRaceButton.SetUpVisual(race_image_default) #setting up visual (the image shown when button is in default state)
        self.MainCharRaceButton.SetDownVisual(race_image_down)  #setting down visual (the image show when button is pressed)
        self.MainCharRaceButton.SetOverVisual(race_image_over)	#setting over visual (the image shown when mouse come over the button)
        self.MainCharRaceButton.SAFE_SetEvent(self.__OnClickMainCharRaceButton) #setting an event to the button defined above
        self.MainCharRaceButton.Show() #the show is necessary to see the button
        
        
    
        
        
        
        

     

     

    In the e.g. i created a button that change its visual based on the player character race.

    WARNING: the code above wont work since the images and the event are invented and they don't exist

     

    • Metin2 Dev 1
    • Love 4
  4. 9 hours ago, Speachless said:

    Hello,

     

    
    int CInputMain::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)

     

    
    	if (ch && ch->IsPC())
    	{
    		if (get_global_time() < ch->analyze_protect)
    		{
    			ch->analyze_protect_count = ch->analyze_protect_count + 1;
    			ch->ChatPacket(CHAT_TYPE_INFO, "<test server> analyze_protect_count. Count %d", ch->analyze_protect_count);
    			
    			if (ch->analyze_protect_count >= 300)
    			{
    				ch->analyze_protect_count = 0;
    				d->SetPhase(PHASE_CLOSE);
    				return (0);
    			}
    		}
    		else
    			ch->analyze_protect_count = 0;
    		
    		ch->analyze_protect = get_global_time() + 1;
    	}

     

    In char.h

     

    
    int analyze_protect; 
    int analyze_protect_count;

     

     

     

    It is missing the initializing of these two values added in char.h.

    They got a random value if you don't set it when CHARACTER object is instancied

    i suggest to add something like :
     

    //SEARCH
    void CHARACTER::Initialize()
    {
    
    //ADD UNDER
    	analyze_protect = 0;
    	analize_protect_count = 0;

     

  5. Hi guys, 

    There's a guy that is blackmailing all servers that are using my offlineshop.

    Not just my clients, but also those who downloaded it from some idiot's leak.

    I'm sharing the fix here as 60/70% of the servers currently open use my shop.

     

    Fix:

    Spoiler
    
    
    //FILE : new_offlineshop_manager.cpp
    //SEARCH FOR
    	bool CShopManager::RecvShopCreateOfferClientPacket(LPCHARACTER ch, TOfferInfo& offer)
    	{
    		if(!ch)
    			return false;
    
    		//offlineshop-updated 03/08/19
    		if(ch->GetPlayerID() == offer.dwOwnerID)
    			return false;
    
    //ADD UNDER
    		// fix flooding offers
    		if (!CheckOfferCooldown(ch->GetPlayerID()))
    			return false;
          
    
          
          
    //SEARCH FOR:  
        void CShopManager::ClearSearchTimeMap()
    	{
    		m_searchTimeMap.clear();
    
    //ADD UNDER
    		// fix flooding offers
    		m_offerCooldownMap.clear();
          
          
          
          
          
          
    //SEARCH FOR      
    	void CShopManager::ClearSearchTimeMap()
    	{
    		m_searchTimeMap.clear();
    	}
    
          
    //ADD UNDER
    	// fix flooding offers
    	bool CShopManager::CheckOfferCooldown(DWORD dwPID) {
    		DWORD now = get_dword_time();
    		const DWORD cooldown_seconds = 15;
    
    		itertype(m_offerCooldownMap) it = m_offerCooldownMap.find(dwPID);
    		if (it == m_offerCooldownMap.end()) {
    			m_offerCooldownMap[dwPID] = now + cooldown_seconds *1000;
    			return true;
    		}
    
    		if (it->second > now)
    			return false;
    
    		it->second = now + cooldown_seconds * 1000;
    		return true;
    	}
         
          
          
          
          
          
    //FILE : new_offlineshop_manager.h
    //SEARCH FOR:
            //search time map (checking to avoid search abouse)
    		void		ClearSearchTimeMap();
    		bool		CheckSearchTime(DWORD dwPID);
    
    //ADD UNDER:
    		// fix flooding offers
    		bool		CheckOfferCooldown(DWORD dwPID);
     
          
          
          
    //SEARCH FOR:
            AUCTIONMAP		m_mapAuctions;
    //ADD UNDER:
    		// fix flooding offers
    		SEARCHTIMEMAP	m_offerCooldownMap;
          
          
    
          
          
    //SEARCH FOR
    int OfflineshopPacketCreateNewShop(LPCHARACTER ch, const char* data, int iBufferLeft)
    {
    	offlineshop::TSubPacketCGShopCreate* pack = nullptr;
    	if(!CanDecode(pack, iBufferLeft))
    		return -1;
    
    	int iExtra=0;
    	data = Decode(pack, data, &iExtra, &iBufferLeft);
    
    	offlineshop::TShopInfo& rShopInfo = pack->shop;
    
      
     
    //ADD UNDER
    	//fix flooding
    	if (rShopInfo.dwCount > 500 || rShopInfo.dwCount == 0) {
    		sys_err("tried to open a shop with 500+ items.");
    		return -1;
    	}
          
          
          
          
          
          
          
    //FILE : ClientManagerOfflineshop.cpp
    //SEARCH FOR:
    
    bool CClientManager::RecvOfflineShopOfferAccepted(const char* data)
    {
    	offlineshop::TSubPacketGDOfferAccept* subpack;
    	data = Decode(subpack, data);
    
    	offlineshop::COfferCache::TOfferCacheInfo* pOffer=nullptr;
    	m_offlineshopOfferCache.Get(subpack->dwOfferID,&pOffer);
      
    //ADD UNDER:
        if(!pOffer)
        	return true;

     

     

     

    Random User :
    Why are u sharing it using metin2dev?

    Answer:
    I m bored to see this guy make money by blackmailing.

     

     

    Random User part2:
    Is it right to share this fix even with those who are not your customer?

     

     

    Answer:
    I honestly think that anyone who uses the shop without permission, taking it from sources different from me, is not worthy of help from me, however I can't even allow so many people to be fooled by this idiot boy.

     

     

    Random User part3:
    Do you know who is blackmailing the p.server founders?

     

    Answer:
    Yes, i know his discord account Mădălin#2332

    I recommend to don't pay him at all. I would like to know other accounts of this guy, if anyone know some please report to me.

    I also have the proofs about what i m talking.

     

     

     

    BIG DISCLAIMER:
    Test the code on a test-sever before to move it on a live-server.

    Thanks to @VegaS™ for the tip about cooldown

    • Love 15
  6. The first numbers are used when your level is 15 (or more) levels higher than monster level (the number 1 means that the basic chance is reduced by a factor 1/100 ).

    The last numbers are used when your level is 15 (or more) levels lower than monster level (the number 1 means that the basic chance is increased by a factor 180/100)

    the numbers in the center (100) is the neutral value (doesn't affect the basic chance to drop the item)

     

    • Love 1
  7. On 3/13/2015 at 8:25 PM, revengertmt said:

    don't work 😐

    Edit:

    how can I make libjpeg????

    in lib directory i have....

     

    and my error is this....

     

     

     

     

    using :

    #pragma comment(lib, <library-name>.lib )

     

    add it to userinterface.cpp (replace <library-name> with the name of your libjpeg obv)

  8. You could download cryptopp library code from the official website.

    You will find the .sln file (Solution) which is to be open with visual studio.

    Once You open it You can compile it.

    Take care to check the Code mode generation to be set on MT for Release and MTd for Debug.

    You can find it by clicking right click on cryptlib project > properties > C++ > Code generation > runtime library 

    After compiled the library move it in your extern/lib and move all .h files (aka headers) on your extern/include/cryptopp (headers and libs are always to be used from the identical version of the library source code)
    Hope i ve explained enoght clearly but for a short recap:
     

    • Download the library source code from the official website.
    • Open the file .sln with visual studio.
    • Check the code generation mode as explained above.
    • Compile the library and move it on extern/lib.
    • Move the headers from the library's source code on your extern/include/cryptopp.
    • Compiler your game again and enjoy.
  9. VERY BIG DISCLAIMER: I m going to show you where the level delta is applied and how they made the constants, but they are used for all monsters, and not only for Stones.

     

     

     

    long answer:
     

    Spoiler

     in game/src/constants.h
     

    
    
    #define PERCENT_LVDELTA(me, victim) aiPercentByDeltaLev[MINMAX(0, (victim + 15) - me, MAX_EXP_DELTA_OF_LEV - 1)]
    #define PERCENT_LVDELTA_BOSS(me, victim) aiPercentByDeltaLevForBoss[MINMAX(0, (victim + 15) - me, MAX_EXP_DELTA_OF_LEV - 1)]

     

     

    as you can see here is calculating a PERCENTAGE to apply to the drop chance which depend on level delta (monster level - player level)

     

    These are macros which are using aiPercentByDeltaLev and aiPercentByDeltaLevForBoss and they are defined in constant.h/constant.cpp.

     

    here is where is calling the macros (item_manager.cpp  ITEM_MANAGER::GetDropPct ):

    
    
    	if (!pkChr->IsStone() && pkChr->GetMobRank() >= MOB_RANK_BOSS)
    		iDeltaPercent = PERCENT_LVDELTA_BOSS(pkKiller->GetLevel(), pkChr->GetLevel());
    	else
    		iDeltaPercent = PERCENT_LVDELTA(pkKiller->GetLevel(), pkChr->GetLevel());

     

     

    here is where the aiPercentByDeltaLev and aiPercentByDeltaLevForBoss are defined (i really don't like how they are defined)  from constants.cpp:

    
    
    const int * aiPercentByDeltaLev = NULL;
    const int * aiPercentByDeltaLevForBoss = NULL;


     

    They are instanced as NULL and they get the real value on runtime by parsing the locale (from locale_service.cpp):

    
    
    void LocaleService_TransferDefaultSetting()
    {
    	if (!check_name)
    		check_name = check_name_euckr;
    
    	if (!is_twobyte)
    		is_twobyte = is_twobyte_euckr;
    
    	if (!exp_table)
    		exp_table = exp_table_common;
    
    	if (!CTableBySkill::instance().Check())
    		exit(1);
    
    	if (!aiPercentByDeltaLevForBoss)
    		aiPercentByDeltaLevForBoss = aiPercentByDeltaLevForBoss_euckr;
    
    	if (!aiPercentByDeltaLev)
    		aiPercentByDeltaLev = aiPercentByDeltaLev_euckr;
    
    	if (!aiChainLightningCountBySkillLevel)
    		aiChainLightningCountBySkillLevel = aiChainLightningCountBySkillLevel_euckr;
    }

     

     

    Finally we can see here that the real array const defined is aiPercentByDelta_euckr and aiPercentByDeltaLevForBoss_euckr, which are defined in constants.cpp:

     

    
    
    
    // MIN(MAX_EXP_DELTA_OF_LEV - 1, (Àû·¾ + 15) - ³»·¾))
    const int aiPercentByDeltaLevForBoss_euckr[MAX_EXP_DELTA_OF_LEV] =
    {
    	1,      // -15  0
    	3,          // -14  1
    	5,          // -13  2
    	7,          // -12  3
    	15,         // -11  4
    	30,         // -10  5
    	60,         // -9   6
    	90,         // -8   7
    	91,         // -7   8
    	92,         // -6   9
    	93,         // -5   10
    	94,         // -4   11
    	95,         // -3   12
    	97,         // -2   13
    	99,         // -1   14
    	100,        // 0    15
    	105,        // 1    16
    	110,        // 2    17
    	115,        // 3    18
    	120,        // 4    19
    	125,        // 5    20
    	130,        // 6    21
    	135,        // 7    22
    	140,        // 8    23
    	145,        // 9    24
    	150,        // 10   25
    	155,        // 11   26
    	160,        // 12   27
    	165,        // 13   28
    	170,        // 14   29
    	180         // 15   30
    };
    
    
    
    const int aiPercentByDeltaLev_euckr[MAX_EXP_DELTA_OF_LEV] =
    {
    	1,  //  -15 0
    	5,  //  -14 1
    	10, //  -13 2
    	20, //  -12 3
    	30, //  -11 4
    	50, //  -10 5
    	70, //  -9  6
    	80, //  -8  7
    	85, //  -7  8
    	90, //  -6  9
    	92, //  -5  10
    	94, //  -4  11
    	96, //  -3  12
    	98, //  -2  13
    	100,    //  -1  14
    	100,    //  0   15
    	105,    //  1   16
    	110,    //  2   17
    	115,    //  3   18
    	120,    //  4   19
    	125,    //  5   20
    	130,    //  6   21
    	135,    //  7   22
    	140,    //  8   23
    	145,    //  9   24
    	150,    //  10  25
    	155,    //  11  26
    	160,    //  12  27
    	165,    //  13  28
    	170,    //  14  29
    	180,    //  15  30
    };

     

     

     

     

     

    short answer:
     

    Spoiler

    from constants.cpp:
     

    
    
    
    // MIN(MAX_EXP_DELTA_OF_LEV - 1, (Àû·¾ + 15) - ³»·¾))
    const int aiPercentByDeltaLevForBoss_euckr[MAX_EXP_DELTA_OF_LEV] =
    {
        1,      // -15  0
        3,          // -14  1
        5,          // -13  2
        7,          // -12  3
        15,         // -11  4
        30,         // -10  5
        60,         // -9   6
        90,         // -8   7
        91,         // -7   8
        92,         // -6   9
        93,         // -5   10
        94,         // -4   11
        95,         // -3   12
        97,         // -2   13
        99,         // -1   14
        100,        // 0    15
        105,        // 1    16
        110,        // 2    17
        115,        // 3    18
        120,        // 4    19
        125,        // 5    20
        130,        // 6    21
        135,        // 7    22
        140,        // 8    23
        145,        // 9    24
        150,        // 10   25
        155,        // 11   26
        160,        // 12   27
        165,        // 13   28
        170,        // 14   29
        180         // 15   30
    };
    
    const int aiPercentByDeltaLev_euckr[MAX_EXP_DELTA_OF_LEV] =
    {
        1,  //  -15 0
        5,  //  -14 1
        10, //  -13 2
        20, //  -12 3
        30, //  -11 4
        50, //  -10 5
        70, //  -9  6
        80, //  -8  7
        85, //  -7  8
        90, //  -6  9
        92, //  -5  10
        94, //  -4  11
        96, //  -3  12
        98, //  -2  13
        100,    //  -1  14
        100,    //  0   15
        105,    //  1   16
        110,    //  2   17
        115,    //  3   18
        120,    //  4   19
        125,    //  5   20
        130,    //  6   21
        135,    //  7   22
        140,    //  8   23
        145,    //  9   24
        150,    //  10  25
        155,    //  11  26
        160,    //  12  27
        165,    //  13  28
        170,    //  14  29
        180,    //  15  30
    };

     

     

     

     

    Conclusions:
    The influence of difference of level on dropping is exactly how you described.

    If my level is lower than the level of the monster/stone i get a drop bonus.

    if my level is equal to the level of the monster/stone i don't get a bonus and neither a malus.

    if my level is higher than level of the monster i get a malus

    • Love 3
  10. 8 minutes ago, ZumbaCafew said:

    Thanks for sharing, where should I put this folder? Thank you 

     

    I usually prefer to put the 3th part libraries on extern folder, but you can move it whenever you want.

    The important thing is to change the -I and -L directives with your directories.

    An example would be:
     

    #Mysql Dynamic 
    LIBDIR += -L../../../extern/lib/mysql
    INCDIR += -I../../../extern/include/mysql
    LIBS += -lmysqlclient
    
    #Mysql Static
    INCDIR += -I../../../extern/include/mysql
    LIBS += ../../../extern/lib/mysql/libmysqlclient.a

     

    the first three lines are for a dynamic linking (it might prefer to link using libmysqlclient.so rather than libmysqlclient.a where both are available)
     

    the second two lines are for a static linking (where we are forcing it to use libmysqlclient.a)

    You can choice the way you prefer.

     

    • Love 1
  11. i ll send you my include and lib folders for mysql80, they are for freebsd 11.3 only (32 bit obv) give me a moment to make the zip

    4 hours ago, ZumbaCafew said:

    I solved the problem thanks to the lib in the mysql 7.x-5.1.35 folder, so I manage to compile, but how can I get the lib for mysql8?

     

    You can't use a lib and an include which are from differents version of mysql... you will get runtime errors (segmentation fault)

  12. On 10/25/2020 at 1:57 AM, ZumbaCafew said:

    linking ../db_r40414_64....
    ld: error: unable to find library -lmysqlclient
    clang-9: error: linker command failed with exit code 1 (use -v to see invocation)
    gmake: *** [Makefile:56: ../db_r40414_64] Error 1

     

    Are you compiling on a i386 machine? or an amd64?
    Amd64 machines will install you the lib built in 64bit which are incompatible with your game and db executables (which you are building in 32bit).

     

     

    On 11/3/2020 at 10:54 PM, ZumbaCafew said:

    ifeq ($(BSD_VERSION), 7) INCDIR += -I../../libmysql/7.x-5.1.35 LIBDIR += -L../../libmysql/7.x-5.1.35 else INCDIR += -I../../libmysql/mysql_8_0_20 LIBDIR += -L../../libmysql/mysql_8_0_20 endif

    Here you changed the -I and -L paths you are adding to LIBDIR and INCDIR, but can u find the lib in the directory you moved to?

  13. On 10/28/2020 at 4:55 PM, TokiSan said:

    char.cpp:8086: error: request for member 'reset' in 'pkMsg', which is of non-class type 'SQLMsg*' char.cpp:8086: error: 'nullptr' was not declared in this scope

    Uhm, yep, nullptr is not declared means you are not using c++11(+) and pkMsg is of non-class type SQLMsg* means you are using .reset on a raw pointer (and .reset is not needed even for smart ptr).

    You solved differently but maybe someone is interested in knowing why errors are received when they are received, as well as knowing how to fix it.

     

     

     

      

    On 11/7/2020 at 2:21 PM, developerares said:

    Is there a problem with this code? I have smart ptr. 

     

    No it is correct. std::unique_ptr<SQLMsg> will delete the memory from heap when its destructor is called. 

    smart pointers have the overload of the operator -> and this help to use them as classic (raw) pointers. (e.g. where you used Msg->Get())

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