Jump to content

piktorvik

Premium
  • Posts

    21
  • Joined

  • Last visited

  • Feedback

    0%

Posts posted by piktorvik

  1. Dear Metin2Dev,

    I believe that many servers are still using old quests for giving mount bonuses from inventory, which are not bad but not very efficient either. Since I haven't seen anyone share something similar yet, I thought I'd share my solution for getting mount bonuses from the inventory.

    You need to specify the bonuses in groups, similar to how you specify mob, etc, special drops. After you have set it up and the item is in your inventory, you will receive the bonus you have set.

    How is a mount's bonus structured?

    locale/germany/mount_bonus_table.txt:
    Group MountTest1
    { 
      vnum 71224 --Mount item vnum from item_proto (type must be ITEM_QUEST (18))
      --You can add maximum 5 bonuses from config (it can be extended) 
      1 13 5  --13 = APPLY_STUN_PCT
      2 14 10 --14 = APPLY_SLOW_PCT 
      3 15 15 --15 = APPLY_CRITICAL_PCT 
      4 16 20 --16 = APPLY_PENETRATE_PCT 
      5 17 25 --17 = APPLY_ATTBONUS_HUMAN 
    }

    This system works with items whose type is ITEM_QUEST (18). It means that your mount item type must be ITEM_QUEST or it won't give you the bonuses. In the future, i'm planning to extend this system for costume mounts, but you can also do it for yourself. I think this is a good starting point for those are using the old quest solutions to give bonuses from inventory. 

    Tutorial:

    CommonDefines.h:

    Spoiler
    #define ADVANCED_MOUNT_BONUS_SYSTEM
    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    #define ADV_MAX_BONUS_COUNT 5 //This allows for a maximum reading of 5 bonuses. However, it can be modified at any time to allow for more bonuses.
    #endif

    char.cpp:

    Spoiler

    Search for RefreshAffect(); in void CHARACTER::ComputePoints() and place below:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    	if (IsPC())
    	{
    		pk_CheckMountBonus.clear();
    		LPITEM pkMountItem;
    
    		for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
    		{
    			if ((pkMountItem = GetInventoryItem(i)) && pkMountItem->GetType() == ITEM_QUEST)
    			{
    				if (std::find(pk_CheckMountBonus.begin(), pk_CheckMountBonus.end(), pkMountItem->GetVnum()) == pk_CheckMountBonus.end())
    				{
    					ITEM_MANAGER::instance().AddMountBonus(this, pkMountItem->GetVnum());
    				}
    			}
    		}
    	}
    #endif

    Add to the end of the file:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    bool CHARACTER::CheckMountBonus(DWORD dwVnum)
    {
    	if (std::find(pk_CheckMountBonus.begin(), pk_CheckMountBonus.end(), dwVnum) == pk_CheckMountBonus.end())
    		return false;
    
    	return true;
    }
    
    bool CHARACTER::AddMountBonus(DWORD dwVnum, bool bAdd)
    {
    	itertype(pk_CheckMountBonus) it = std::find(pk_CheckMountBonus.begin(), pk_CheckMountBonus.end(), dwVnum);
    
    	if (it == pk_CheckMountBonus.end())
    	{
    		if (bAdd)
    		{
    			pk_CheckMountBonus.push_back(dwVnum);
    		}
    	}
    	else
    	{
    		if (!bAdd)
    		{
    			pk_CheckMountBonus.erase(it);
    		}
    	}
    
    	return true;
    }
    
    #endif

    char.h:

    Spoiler

    Search for DragonSoul_RefineWindow_CanRefine(); and add below:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    	protected:
    		std::vector<DWORD> pk_CheckMountBonus;
    	public:
    		bool CheckMountBonus(DWORD dwVnum);
    		bool AddMountBonus(DWORD dwVnum, bool bAdd);
    #endif

    char_item.cpp:

    Spoiler

    Search for this in void CHARACTER::SetItem

    	if (pItem && pItem->GetOwner())
    	{
    		assert(!"GetOwner exist");
    		return;
    	}

    Add this below:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    	if (pItem && window_type == INVENTORY && wCell < INVENTORY_MAX_NUM)
    	{
    		if (pItem->GetType() == ITEM_QUEST)
    		{
    			ITEM_MANAGER::instance().AddMountBonus(this, pItem->GetVnum());
    		}
    	}
    #endif

    input_db.cpp:

    Spoiler

    Search for:

    	snprintf(szDragonSoulTableFileName, sizeof(szDragonSoulTableFileName),
    		"%s/dragon_soul_table.txt", LocaleService_GetBasePath().c_str());

    And add this below:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    	char szMountBonusTableFileName[FILE_NAME_LEN];
    	snprintf(szMountBonusTableFileName, sizeof(szMountBonusTableFileName),
    		"%s/mount_bonus_table.txt", LocaleService_GetBasePath().c_str());
    #endif

    Search for:

    	if (!ITEM_MANAGER::instance().ReadMonsterDropItemGroup(szMOBDropItemFileName))
    	{
    		sys_err("cannot load MOBDropItemFile: %s", szMOBDropItemFileName);
    		thecore_shutdown();
    		return;
    	}

    And add this below:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    	sys_log(0, "LoadLocaleFile: MountBonusInvFile: %s", szMountBonusTableFileName);
    	if (!ITEM_MANAGER::instance().ReadMountBonusConfig(szMountBonusTableFileName))
    	{
    		sys_err("cannot load MountBonusInventoryConfigFile: %s", szMountBonusTableFileName);
    	}
    #endif

    item.cpp:

    Spoiler

    Search for LPCHARACTER pOwner = m_pOwner; in CItem:RemoveFromCharacter() and add below:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    	if (GetType() == ITEM_QUEST)
    	{
    		bool bCanRemove = true;
    		LPITEM pkMountItem;
    
    		for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
    		{
    			if ((pkMountItem = pOwner->GetInventoryItem(i)) && pkMountItem->GetVnum() == GetVnum())
    			{
    				if (!(GetID() == pkMountItem->GetID()))
    				{
    					bCanRemove = false;
    					break;
    				}
    			}
    		}
    
    		if (bCanRemove)
    			ITEM_MANAGER::instance().AddMountBonus(pOwner, GetVnum(), false);
    	}
    #endif

    item_manager.cpp:

    Spoiler

    Add to the end of the file:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    bool ITEM_MANAGER::ReadMountBonusConfig(const char* c_pszFileName)
    {
    	m_map_mount_bonus.clear();
    	CTextFileLoader loader;
    
    	if (!loader.Load(c_pszFileName))
    		return false;
    
    	std::string stName;
    
    	for (DWORD i = 0; i < loader.GetChildNodeCount(); ++i)
    	{
    		loader.SetChildNode(i);
    		loader.GetCurrentNodeName(&stName);
    
    		int iVnum = 0;
    		if (!loader.GetTokenInteger("vnum", &iVnum))
    		{
    			sys_err("ReadMountBonusConfig : Syntax error %s : no vnum, node %s", c_pszFileName, stName.c_str());
    			loader.SetParentNode();
    			return false;
    		}
    
    		PKMountBonusInfo pk_MountBonus;
    
    		char buf[4];
    		TTokenVector* pTok;
    		for (int k = 1; k < ADV_MAX_BONUS_COUNT + 1; ++k)
    		{
    			snprintf(buf, sizeof(buf), "%d", k);
    
    			pk_MountBonus.bType[k - 1] = 0;
    			pk_MountBonus.lValue[k - 1] = 0;
    
    			if (loader.GetTokenVector(buf, &pTok))
    			{
    				int apply = 0;
    				str_to_number(apply, pTok->at(0).c_str());
    
    				int value = 0;
    				str_to_number(value, pTok->at(1).c_str());
    
    				pk_MountBonus.bType[k - 1] = apply;
    				pk_MountBonus.lValue[k - 1] = value;
    			}
    		}
    
    		m_map_mount_bonus[iVnum] = pk_MountBonus;
    
    		loader.SetParentNode();
    	}
    
    	return true;
    }
    
    bool ITEM_MANAGER::AddMountBonus(LPCHARACTER ch, DWORD dwVnum, bool bAdd)
    {
    	if (ch == NULL)
    		return false;
    
    	if (bAdd && ch->CheckMountBonus(dwVnum))
    	{
    		return false;
    	}
    
    	if (bAdd == false && ch->CheckMountBonus(dwVnum) == false)
    	{
    		return false;
    	}
    
    	auto it = m_map_mount_bonus.find(dwVnum);
    	if (it == m_map_mount_bonus.end())
    		return false;
    
    	ch->AddMountBonus(dwVnum, bAdd);
    
    	for (int i = 0; i < ADV_MAX_BONUS_COUNT; ++i)
    	{
    		if (it->second.bType[i] > 0 && it->second.lValue[i] > 0)
    		{
    			if (bAdd)
    				ch->ApplyPoint(it->second.bType[i], it->second.lValue[i]);
    			else
    				ch->ApplyPoint(it->second.bType[i], -it->second.lValue[i]);
    		}
    	}
    
    	return true;
    }
    
    #endif

    item_manager.h:

    Spoiler

     

    Search for:

    	public:
    		DWORD	GetMaskVnum(DWORD dwVnum);
    		std::map<DWORD, TItemTable>  m_map_vid;
    		std::map<DWORD, TItemTable>&  GetVIDMap() { return m_map_vid; }
    		std::vector<TItemTable>& GetVecProto() { return m_vec_prototype; }
    		bool ReadItemVnumMaskTable(const char * c_pszFileName);

    And add this above:

    #ifdef ADVANCED_MOUNT_BONUS_SYSTEM
    		struct PKMountBonusInfo
    		{
    			BYTE bType[ADV_MAX_BONUS_COUNT];
    			long long int lValue[ADV_MAX_BONUS_COUNT];
    		};
    
    	public:
    		bool ReadMountBonusConfig(const char* c_pszFileName);
    		bool AddMountBonus(LPCHARACTER ch, DWORD dwVnum, bool bAdd = true);
    
    	protected:
    		std::map<DWORD, PKMountBonusInfo> m_map_mount_bonus;
    #endif

    If you have any ideas on how to make this system better, please leave a comment. 

    I hope this will be useful for you. 🙂

     

    Best Regards,

    piktorvik

    • Metin2 Dev 4
    • Eyes 1
    • Good 1
    • muscle 1
    • Love 4
  2. Hey guys,

    Today I was facing with a guild melting problem, the problem was that the stones which are in the special inventory is not shown in the SelectItemWindow. I managed to solve this by adding a new check for special inventory size && special inventory slot end.

    In this tutorial the codes may be different from yours, if you have Sanii Special Inventory you have to check your GameType.h how is page size calculated and your PythonPlayerModule.cpp to see how it's defined.

    For example:

    PythonPlayerModule.cpp->
    PyModule_AddIntConstant(poModule, "SPECIAL_INVENTORY_PAGE_SIZE", SPECIAL_INVENTORY_PAGE_SIZE);
    PyModule_AddIntConstant(poModule, "SPECIAL_INVENTORY_SLOT_END", c_Special_Inventory_Slot_End);
    
    GameType.h->
    SPECIAL_INVENTORY_WIDTH = 5,
    SPECIAL_INVENTORY_HEIGHT = 9,
    SPECIAL_INVENTORY_PAGE_SIZE = SPECIAL_INVENTORY_WIDTH * SPECIAL_INVENTORY_HEIGHT,
    
    const DWORD c_Special_Inventory_Slot_Start = c_Belt_Inventory_Slot_End;
    const DWORD c_Special_Inventory_Skillbook_Slot_Start = c_Special_Inventory_Slot_Start;
    const DWORD c_Special_Inventory_Skillbook_Slot_End = c_Special_Inventory_Skillbook_Slot_Start +SPECIAL_INVENTORY_PAGE_SIZE * c_Inventory_Page_Count;
    const DWORD c_Special_Inventory_Stone_Slot_Start = c_Special_Inventory_Skillbook_Slot_End;
    const DWORD c_Special_Inventory_Stone_Slot_End = c_Special_Inventory_Stone_Slot_Start + SPECIAL_INVENTORY_PAGE_SIZE * c_Inventory_Page_Count;
    const DWORD c_Special_Inventory_Material_Slot_Start = c_Special_Inventory_Stone_Slot_End;
    const DWORD c_Special_Inventory_Material_Slot_End = c_Special_Inventory_Material_Slot_Start + SPECIAL_INVENTORY_PAGE_SIZE * c_Inventory_Page_Count;
    const DWORD c_Special_Inventory_Slot_End = c_Special_Inventory_Material_Slot_End;
    
    const DWORD c_Inventory_Count = c_Special_Inventory_Slot_End;

     

    Solution:

    root/uiselect.py

    In def RefreshSlot(self): search for:
    	for i in xrange(player.INVENTORY_PAGE_SIZE*player.INVENTORY_PAGE_COUNT):
          
    After for loop add a new for loop for the special inventory:
    		for i in xrange(player.SPECIAL_INVENTORY_PAGE_SIZE*player.SPECIAL_INVENTORY_SLOT_END):
    			slotNumber = i
    
    			itemVNum = getItemVNum(slotNumber)
    			if 0 == itemVNum:
    				continue
    
    			if not item.IsMetin(itemVNum):
    				continue
    
    			itemGrade = player.GetItemGrade(slotNumber)
    			if itemGrade > 2:
    				continue
    
    			self.inventorySlotPosDict[slotPos] = i
    
    			slotPos += 1
    
    			if slotPos > 54:
    				break

     

    Another problem is that if you select 100 stack of stone in the SelectItemWindow, they all disappear from the inventory, so instead of one piece, all of them disappear. 

    Solution:

    mining.cpp

    Search for:
    ITEM_MANAGER::instance().RemoveItem(metinstone_item, "REMOVE (MELT)");
    
    Replace with:
    metinstone_item->SetCount(metinstone_item->GetCount() - 1);

    I hope it will be useful for you 🙂  Author of special inventory: @Sanii.

    @LordZiege approved me to share this fix.

    • Metin2 Dev 1
    • Love 2
  3. Dear everyone!😃

    I'm trying to solve this issue, but i didn't find anything. I'm ask for your help guys maybe someone can suggest something.

    Serverfile: martysama 5.4 (boughted).

    In the source i have vegas multilanguage + pickup (boughted).

    LLDB:

    spacer.png

    input_login.cpp 85 line (sometimes it's item_drop_bonus etc..):

        exp_bonus = CPrivManager::instance().GetPriv(ch, PRIV_EXP_PCT);

    it's chatpacket:

    ch->ChatPacket(CHAT_TYPE_NOTICE,
                LC_TEXT("°ćÇčġ %d%% Ăß°ˇ Čąµć ŔĚşĄĆ® ÁßŔÔ´Ď´Ů."), exp_bonus);

    (When entering the game i see this chat message and it's working fine.)

     

    GDB:

    spacer.png

     

    Syslog:
     

    Quote

    Sep  1 09:10:47 :: SHOW: Poison 723756x502591x0
    Sep  1 09:10:47 :: AddAffect Poison type 215 apply 0 0 flag 28 duration 5
    Sep  1 09:10:47 :: ENTERGAME: Poison 723756x502591x0 45.134.238.92 map_index 71
    Sep  1 09:10:47 :: HORSE STAMINA CONSUME EVENT CANCEL 0x0 -> NULL
    Sep  1 09:10:47 :: HORSE STAMINA REGEN EVENT CREATE 0x31f90100
    Sep  1 09:10:47 :: SendLandList map 71 count 0 elem_size: 0

    What do you think? The server is crashing very often when someone entering the game. 

    I've checked the locale_strings line by line, translates, source chatpackets, but i didn't find the issue.

    Marty and VegaS tried to help me, but it was not enough.

     

    I don't expect anyone to help me for free. I can pay for your help & time.

    Thank you in advance!

  4. On 6/7/2021 at 2:51 AM, Kinesia said:

    Hi , i get this error in VS 2019, compiling the source binary. 

     

    C1047 The object Library/discord_rpc_r.lib was made it with a version of the compiler  than the other objects, like "Distribute / AccountConnector.obj". You must have to compile all the objects and librarys in the same compiler. 

    How i can found the right version ? 

    Sorry for my english. 

    Thanks

     

    HI Kinesia,

     

    You can find a tutorial here for implement the Discord RPC. 

    You need to compile the libs with the same platform toolset as your client source builded.

    Blackdragonx61 has made a tutorial about how to build the libs.

     

    I hope it will help you.

     

    • Metin2 Dev 1
  5. Hi.

     

    I have this problem.

     

    Quote

    In function `CExchange::Cancel()':
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:916: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    OBJDIR/exchange.o: In function `CExchange::Accept(bool)':
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:907: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:908: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    OBJDIR/exchange.o: In function `CExchange::AddGold(long)':
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:256: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:273: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    OBJDIR/exchange.o:/usr/src/mainline/Srcs/Server/game/src/exchange.cpp:274: more undefined references to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)' follow
    OBJDIR/exchange.o: In function `CExchange::Cancel()':
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:916: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    OBJDIR/exchange.o: In function `CExchange::Accept(bool)':
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:907: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:908: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    OBJDIR/exchange.o: In function `CExchange::AddGold(long)':
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:256: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    /usr/src/mainline/Srcs/Server/game/src/exchange.cpp:273: undefined reference to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)'
    OBJDIR/exchange.o:/usr/src/mainline/Srcs/Server/game/src/exchange.cpp:274: more undefined references to `exchange_packet(CHARACTER*, unsigned char, bool, unsigned int, SItemPos, unsigned int, void*)' follow
     

     

    tutorial:

    Quote

    // 1. Replace this function:
    // ********************************* BEGIN ********************************* //
    void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, long long arg1, TItemPos arg2, DWORD arg3, void * pvData)
    {
        if (!ch->GetDesc())
            return;

        struct packet_exchange pack_exchg;
        pack_exchg.header         = HEADER_GC_EXCHANGE;
        pack_exchg.sub_header     = sub_header;
        pack_exchg.is_me        = is_me;
        pack_exchg.arg1            = arg1;
        pack_exchg.arg2            = arg2;
        pack_exchg.arg3            = arg3;

        if (sub_header == EXCHANGE_SUBHEADER_GC_ITEM_ADD && pvData)
        {
            thecore_memcpy(&pack_exchg.alSockets, ((LPITEM) pvData)->GetSockets(), sizeof(pack_exchg.alSockets));
            thecore_memcpy(&pack_exchg.aAttr, ((LPITEM) pvData)->GetAttributes(), sizeof(pack_exchg.aAttr));
        }
        else
        {
            memset(&pack_exchg.alSockets, 0, sizeof(pack_exchg.alSockets));
            memset(&pack_exchg.aAttr, 0, sizeof(pack_exchg.aAttr));
        }

        ch->GetDesc()->Packet(&pack_exchg, sizeof(pack_exchg));
    }
    // ********************************** END ********************************** //
    // With this:
    // ********************************* BEGIN ********************************* //
    void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, long long arg1, TItemPos arg2, DWORD arg3, void * pvData)
    {
        if (!ch->GetDesc())
            return;

        struct packet_exchange pack_exchg;
        pack_exchg.header         = HEADER_GC_EXCHANGE;
        pack_exchg.sub_header     = sub_header;
        pack_exchg.is_me        = is_me;
        pack_exchg.arg1            = arg1;
        pack_exchg.arg2            = arg2;
        pack_exchg.arg3            = arg3;

        if (sub_header == EXCHANGE_SUBHEADER_GC_ITEM_ADD && pvData)
        {
    #ifdef WJ_ENABLE_TRADABLE_ICON
            pack_exchg.arg4 = TItemPos(((LPITEM) pvData)->GetWindow(), ((LPITEM) pvData)->GetCell());
    #endif
            thecore_memcpy(&pack_exchg.alSockets, ((LPITEM) pvData)->GetSockets(), sizeof(pack_exchg.alSockets));
            thecore_memcpy(&pack_exchg.aAttr, ((LPITEM) pvData)->GetAttributes(), sizeof(pack_exchg.aAttr));
        }
        else
        {
    #ifdef WJ_ENABLE_TRADABLE_ICON
            pack_exchg.arg4 = TItemPos(RESERVED_WINDOW, 0);
    #endif
            memset(&pack_exchg.alSockets, 0, sizeof(pack_exchg.alSockets));
            memset(&pack_exchg.aAttr, 0, sizeof(pack_exchg.aAttr));
        }

        ch->GetDesc()->Packet(&pack_exchg, sizeof(pack_exchg));
    }
    // ********************************** END ********************************** //
     

     

    Any idea :\?

  6. On 2/7/2021 at 7:35 PM, Cappuccino said:

    This is a little tutorial on how to connect the game to the item shop of your website.

    By clicking on the coin in the game client the web browser will be opened and connected to your website.

    I'll explain how to automatically login the player to the item shop :)

     

    First of all open cmd_general.cpp and look for do_in_game_mall and replace the whole function with this

     

    
    
    
    ACMD(do_in_game_mall)
    {
    		char buf[512+1];
    		char sas[33];
    		MD5_CTX ctx;
    
    		const char secretKey[] = "my secret key"; // <<--- EDIT THIS!!!
    		const char websiteUrl[] = "http://mywebsite/shop"; // <<--- EDIT THIS!!!
    
    		snprintf(buf, sizeof(buf), "%u%s", ch->GetAID(), secretKey);
    
    		MD5Init(&ctx);
    		MD5Update(&ctx, (const unsigned char *) buf, strlen(buf));
    #ifdef __FreeBSD__
    		MD5End(&ctx, sas);
    #else
    		static const char hex[] = "0123456789abcdef";
    		unsigned char digest[16];
    		MD5Final(digest, &ctx);
    		int i;
    		for (i = 0; i < 16; ++i) {
    			sas[i+i] = hex[digest[i] >> 4];
    			sas[i+i+1] = hex[digest[i] & 0x0f];
    		}
    		sas[i+i] = '\0';
    #endif
    
    		snprintf(buf, sizeof(buf), "mall %s?aid=%u&secret=%s", websiteUrl, ch->GetAID(), sas);
    
    		ch->ChatPacket(CHAT_TYPE_COMMAND, buf);
    }

     

    Edit secretKey and websiteUrl with your information. The key can be a random string.

     

    What happens is the following:

    • aid = account id
    • secret = md5( account id + your secret key )

     

    So your website you can check if the secret is corrent and then login the player. You can do something like this:

     

    
    
    <?php
    
    $secretKey = $_GET['secret'];
    $accountId = $_GET['aid'];
    
    $generatedSecret = md5($accountId . $secretKey);
    
    if ($generatedSecret == $secretKey) {
        // ok, proceed with login
    } else {
        // invalid secret
    }

     

    Thanks for share this. I tested it with Chromium, and it works! 

  7. 14 hours ago, Ikarus_ said:

    I can't tell you how to solve it, i can just try to explain you what's happen here:
     

    
    LUA_ERROR: locale/hungary/quest/object/state/mb_igshop:984: attempt to call field `give_item_with' (a nil value)

     

    The Error is saying us that a quest is calling give_item_with (i guess you might find it as pc.give_item_with) which is not defined in the module (it might be pc module) and the attempt to call it returned a nil value (because can't find its function body defined). 
    The way to solve it is to define the body of the function.

    Usually the lua modules are defined by passing a function table e.g. here we have:

     

    
    void RegisterPCFunctionTable()
    {
      luaL_reg pc_functions[] =
        {
        { "get_wear",		pc_get_wear			},
        { "get_player_id",	pc_get_player_id	},
        { "get_account_id", pc_get_account_id	},
        { "get_account",	pc_get_account		},
        //[........]
        //[........]
        //[........]			
        { NULL,			NULL			}
      };
    
      CQuestManager::instance().AddLuaFunctionTable("pc", pc_functions);
    }

     

    As you can see here we have a list of methods defined by giving them a name (callable from lua) and a definition which is defined in the .cpp file (e.g. questlua_pc.cpp)

     

    Conclusion is that you need to define your function which is giving you that error and to add it to the appropriate function table.

     

    Thats my RegisterPCFunctionTable()

        void RegisterPCFunctionTable()
        {
            luaL_reg pc_functions[] = 
            {
    /////////ETC,ETC/////////////////

                { "get_channel_id",        pc_get_channel_id    },

                { "give_poly_marble",    pc_give_poly_marble    },
                { "get_sig_items",        pc_get_sig_items    },

                { "charge_cash",        pc_charge_cash        },
                
                { "get_informer_type",    pc_get_informer_type    },    //µ¶ŔĎ Ľ±ą° ±â´É
                { "get_informer_item",  pc_get_informer_item    },

                { "give_award",            pc_give_award            },    //ŔĎş» °čÁ¤´ç ÇŃąřľż ±Ý±« Áö±Ţ
                { "give_award_socket",    pc_give_award_socket    },    //¸ô ŔÎşĄĹ丮żˇ ľĆŔĚĹŰ Áö±Ţ. ĽŇÄĎ ĽłÁ¤Ŕ» Ŕ§ÇŃ ÇÔĽö.

                { "get_killee_drop_pct",    pc_get_killee_drop_pct    }, /* mob_vnum.kill ŔĚşĄĆ®żˇĽ­ killeeżÍ pcżÍŔÇ level Â÷ŔĚ, pcŔÇ ÇÁ¸®ąĚľö µĺ¶ř·ü µîµîŔ» °í·ÁÇŃ ľĆŔĚĹŰ µĺ¶ř Č®·ü.
                { "give_item_with", pc_give_item_with },                                                        * return °ŞŔş (şĐŔÚ, şĐ¸đ).
                                                                        * (¸»ŔĚ şąŔâÇѵĄ, CreateDropItemŔÇ GetDropPctŔÇ iDeltaPercent, iRandRange¸¦ returnÇŃ´Ů°í ş¸¸é µĘ.)                                                        * (ŔĚ ¸»ŔĚ ´ő ľî·Áżď¶ółŞ ¤Đ¤Đ)
                                                                        * ÁÖŔÇ»çÇ× : kill eventżˇĽ­¸¸ »çżëÇŇ °Í!
                                                                        */

                { NULL,            NULL            }
            };

            CQuestManager::instance().AddLuaFunctionTable("pc", pc_functions);
        }
    };
     

    Any other solution? 😕

  8. Hi Metin2Dev,

     

    I need help with this:

    20:20:57.867740 :: RunState: LUA_ERROR: locale/hungary/quest/object/state/mb_igshop:984: attempt to call field `give_item_with' (a nil value)
    SYSERR: Oct 30 20:20:57.867829 :: WriteRunningStateToSyserr: LUA_ERROR: quest mb_igshop.start click

     

     

    This happens when someone buys the product I am offering for sale and wants to take it out or when I just want to smoothly withdraw a sale.

     

    Please help me! Thanks! Have a nice day!

  9. 12 minutes ago, Catalin2o14 said:

    in the idea that you have nothing wrong with header and quests,

    trucate these table from player https://metin2.download/picture/mcSI0DzEZt7F7zOehBB37Z2Rrzn7vjHc/.png

     

    if not working, replace them

    Its not work ? Any idea? I will try replace the tables but i think its not fix it

    42 minutes ago, Catalin2o14 said:

    in the idea that you have nothing wrong with header and quests,

    trucate these table from player https://metin2.download/picture/mcSI0DzEZt7F7zOehBB37Z2Rrzn7vjHc/.png

     

    if not working, replace them

    Solved. The problem is guild.cpp INSERT query :)

        for (int i = 0; i < GUILD_GRADE_COUNT; ++i)
        {
            DBManager::instance().Query("INSERT INTO guild_grade VALUES(%u, %d, '%s', %d)", 
                    get_table_postfix(),
                    m_data.guild_id, 
                    i + 1, 
                    m_data.grade_array.grade_name, 
                    m_data.grade_array.auth_flag);
        }

     

    to: 

     

        for (int i = 0; i < GUILD_GRADE_COUNT; ++i)
        {
            DBManager::instance().Query("INSERT INTO guild_grade%s VALUES(%u, %d, '%s', %d)", 
                    get_table_postfix(),
                    m_data.guild_id, 
                    i + 1, 
                    m_data.grade_array.grade_name, 
                    m_data.grade_array.auth_flag);
        }

    • Angry 1
  10. Hi everyone!

    I found a problem with guild making.

    spacer.png

     

    If someone wants to make a guild, and if he enter the guild name and press OK the channel1_1 will crash.

    Channel1_1 syserr is empty.

     

    DB Syserr: SYSERR: Aug 20 21:03:36.172297 :: Process: FDWATCH: peer null in event: ident 22 

     

    I tried debuging the game.core but I didn't get anything

     

    Please help! Have a nice day!

     

     

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