Jump to content

AZICKO

Management
  • Posts

    1510
  • Joined

  • Days Won

    13
  • Feedback

    100%

Posts posted by AZICKO

  1. Metin2 Download has been updated!
    Update 4.5.0 for Metin2 Download...

    Bug fixes & Minor changes

    • Deleted Server type: Master or Slave
    • Virus Total API have been fixed
    • PHP warnings have been fixed
    • Translator class have been fixed
    • Router class have been fixed
    • SQL Error on Picture class have been fixed
    • SQL Error on Dashboard class have been fixed
    • SQL errors are now caught for platform administrators
    • Harmonization of SQL table and column names (Since version 3.X.X)
    • IP address is now logged when uploading an image
    • Adding, removing and modifying translations
    • HTTP Class has been rewritten
    • Miscellaneous fixes
    • CSS Optimisation
    • Code cleanup

    New Features

    • Share X API
    • Report System for pictures and files
      • https://metin2.download/file/{key}/report/
      • https://metin2.download/picture/{key}/report/
    • Permissions System based on access roles (deployment in progress)
    • Bottom navigation

     

    Share X API - Configuration

    You must have an account on Metin2 Download to use the Share X API!

    Spoiler

    .png

     

    Name: Metin2 Download
    Destination type: Image uploader
    Method: POST
    Request URL: https://metin2.download/api/share-x/1/
    
    Body: Form data (multipart/form-data)
    email: The email address of your Metin2 Download account
    password: the password of your Metin2 Download account
    
    File from name: picture
    URL: {json:data.url}
    Error message: {json:data.response}

     

    .png

     

    Share X API - Recommended Setup

    Spoiler

    .png

    .png

    • Metin2 Dev 2
    • Scream 1
  2. Someone has their Discord Tag and Discord Account ID (you need to be in developer mode to retrieve it).
    I will associate it with the Pillory.

    # Topic's Merged

    • Smile Tear 1
    • Love 1
    • Pillory Updated
      • Dark theme and possibility to search for duplicate accounts of a banned account.
      • It makes the difference between a ban, a member flagged as a spammer and an anomaly on the account during the ban.
    • Feedbacks forum deleted
      • You can suggest ideas by private message, on the discord server or via ticket on the discord server.
    • Disputes forum deleted
      • From now on, a dispute must be sent by private message to all staff members or via ticket on the discord server.
  3. Yesterday was a special day...
    Warning Day! 🤣

     

    Please wear your sunglasses!

     

    I wrote a new pillory system in JS with DataTable. To be honest, I was lazy to keep the pillory up to date with the latest bans. Now, this new pillory directly queries Metin2 Dev's database. Unlike the old system, you can view all bans since the forum opened (except pardoned members). You will see several information there, member name, reasons for the ban (warnings issued by the staff), discord account id (if the member had synchronized it) and finally, the date of the last warning. Moderators no longer need to warn the member and create a topic in the pillory. From now on, in case of banishment, they will warn the member several times according to the most serious reasons (Reselling, Scamming, Leaking...).

    Many Metin2 Dev sellers have already asked me if a potential customer was suspicious. From now on, you will be able to search and filter the results according to the information contained in the pillory.

     

    I also wrote a new system to search for members within the community. You can search for a member by several criteria: Metin2 Dev ID, Metin2 Dev Name, Discord ID or Discord Tag. If the member you are looking for is banned from our community, a link to the pillory will be available to view the reasons for the ban. The goal is to improve the accessibility of information about toxic members (Reseller, Scammer, Leaker...) of the Metin2 community and to protect our members from these dishonest members.

     

     All information displayed is already public.

    • Love 2
  4. 6 minutes ago, soxis94 said:

    Hi @ TMP4, i have a problem with the DB, when i start MySQL 8.0 on FreeBSD 13.1 x64:

     

    # service mysql-server start
    Starting mysql.
     # service mysql-server status
    mysql is not running.

     

    in my /var/db/mysql  *.err :

      Hide contents

    2022-05-13T15:58:26.6NZ mysqld_safe Logging to '/var/db/mysql/AwakenII.err'.
    2022-05-13T15:58:26.6NZ mysqld_safe Starting mysqld daemon with databases from /var/db/mysql
    2022-05-13T15:58:27.503003Z 0 [Warning] [MY-011068] [Server] The syntax 'slave_load_tmpdir' is deprecated and will be removed in a future release. Please use replica_load_tmpdir instead.
    2022-05-13T15:58:27.503113Z 0 [Warning] [MY-011069] [Server] The syntax '--master-info-repository' is deprecated and will be removed in a future release.
    2022-05-13T15:58:27.503182Z 0 [Warning] [MY-011069] [Server] The syntax '--relay-log-info-repository' is deprecated and will be removed in a future release.
    2022-05-13T15:58:27.503322Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
    2022-05-13T15:58:27.503703Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
    2022-05-13T15:58:27.503802Z 0 [Warning] [MY-011068] [Server] The syntax 'slave_load_tmpdir' is deprecated and will be removed in a future release. Please use replica_load_tmpdir instead.
    2022-05-13T15:58:27.503891Z 0 [Warning] [MY-011069] [Server] The syntax '--master-info-repository' is deprecated and will be removed in a future release.
    2022-05-13T15:58:27.503940Z 0 [Warning] [MY-011069] [Server] The syntax '--relay-log-info-repository' is deprecated and will be removed in a future release.
    2022-05-13T15:58:27.504068Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
    2022-05-13T15:58:27.504387Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
    2022-05-13T15:58:27.512483Z 0 [System] [MY-010116] [Server] /usr/local/libexec/mysqld (mysqld 8.0.29) starting as process 28069
    2022-05-13T15:58:27.645031Z 0 [Warning] [MY-000054] [Server] World-writable config file '/var/db/mysql/auto.cnf' is ignored.
    2022-05-13T15:58:27.646034Z 0 [Warning] [MY-010107] [Server] World-writable config file '/var/db/mysql/auto.cnf' has been removed.
    2022-05-13T15:58:27.647228Z 0 [Warning] [MY-010075] [Server] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 87008867-d2d5-11ec-92c9-dca632fa7384.
    2022-05-13T15:58:27.673038Z 1 [System] [MY-011012] [Server] Starting upgrade of data directory.
    2022-05-13T15:58:27.673202Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
    2022-05-13T15:58:28.267872Z 1 [ERROR] [MY-012263] [InnoDB] The Auto-extending innodb_system data file '/var/db/mysql/ibdata1' is of a different size 1152 pages (rounded down to MB) than specified in the .cnf file: initial 8192 pages, max 0 (relevant if non-zero) pages!
    2022-05-13T15:58:28.268142Z 1 [ERROR] [MY-012930] [InnoDB] Plugin initialization aborted with error Generic error.
    2022-05-13T15:58:28.271297Z 1 [ERROR] [MY-011013] [Server] Failed to initialize DD Storage Engine.
    2022-05-13T15:58:28.272647Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.
    2022-05-13T15:58:28.273443Z 0 [ERROR] [MY-010119] [Server] Aborting
    2022-05-13T15:58:28.287337Z 0 [System] [MY-010910] [Server] /usr/local/libexec/mysqld: Shutdown complete (mysqld 8.0.29)  Source distribution.
    2022-05-13T15:58:28.6NZ mysqld_safe mysqld from pid file /var/db/mysql/AwakenII.pid ended
     

     

    i can change the my.conf configuration for reduce the ibdata1 dimension to 18M but if i change this, return the error "Redo log is compatible for MySQL ver 5.7 bla bla bla..."

    Help me pleasee.
     

    MySQL 8 is good, but... You need to modify some SQL queries (wrap some column names) in Metin2 sources to be compatible with MySQL 8, and password function.

  5. This fixes several issues :

    • Unable to destroy an item from the Dragon Soul Inventory
    • A second dialog box appears asking for confirmation before destroying the item
    • When you give yourself any stackable item and split the stack, you can drop the splitted stack in correct amounts, but you cannot destroy a splitted stack, you will always be forced to destroy the whole stack

     

    Client/Local_inc.h

    Add :

    #define M2_FEATURE_DESTROY_ITEM

    Client/Packet.h

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	HEADER_CG_ITEM_DESTROY						= 21,
    #endif

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	typedef struct command_item_destroy
    	{
    		BYTE		header;
    		TItemPos	pos;
    		BYTE        	count;
    	} TPacketCGItemDestroy;
    #endif

    Client/PythonApplicationModule.cpp

    Add :

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

    Client/PythonNetworkStream.h

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    		bool SendItemDestroyPacket(TItemPos pos, DWORD count);
    #endif

    Client/PythonNetworkStramModule.cpp

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	PyObject* netSendItemDestroyPacket(PyObject* poSelf, PyObject* poArgs)
    	{
    		TItemPos Cell;
    		int count;
    		switch (PyTuple_Size(poArgs))
    		{
    		case 2:
    			if (!PyTuple_GetInteger(poArgs, 0, &Cell.cell))
    				return Py_BuildException();
    			if (!PyTuple_GetInteger(poArgs, 1, &count))
    				return Py_BuildException();
    
    			break;
    		case 3:
    			if (!PyTuple_GetByte(poArgs, 0, &Cell.window_type))
    				return Py_BuildException();
    			if (!PyTuple_GetInteger(poArgs, 1, &Cell.cell))
    				return Py_BuildException();
    			if (!PyTuple_GetInteger(poArgs, 2, &count))
    				return Py_BuildException();
    
    			break;
    		default:
    			return Py_BuildException();
    		}
    		CPythonNetworkStream& rkNetStream = CPythonNetworkStream::Instance();
    		rkNetStream.SendItemDestroyPacket(Cell, count);
    		return Py_BuildNone();
    	}
    #endif

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    		{ "SendItemDestroyPacket",				netSendItemDestroyPacket,				METH_VARARGS },
    #endif

    Client/PythonNetworkStreamPhaseGameItem.cpp

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	bool CPythonNetworkStream::SendItemDestroyPacket(TItemPos pos, DWORD count)
    	{
    		if (!__CanActMainInstance())
    			return true;
    
    		TPacketCGItemDestroy itemDestroyPacket;
    		itemDestroyPacket.header = HEADER_CG_ITEM_DESTROY;
    		itemDestroyPacket.pos = pos;
    		itemDestroyPacket.count = count;
    
    		if (!Send(sizeof(itemDestroyPacket), &itemDestroyPacket))
    		{
    			Tracen("SendItemDestroyPacket Error");
    			return false;
    		}
    		return SendSequence();
    	}
    #endif

    Server/service.h

    Add :

    #define M2_FEATURE_DESTROY_ITEM

    Server/char_item.cpp

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	bool CHARACTER::DestroyItem(TItemPos Cell, BYTE bCount)
    	{
    		LPITEM item = NULL;
    		if (!CanHandleItem())
    		{
    			if (NULL != DragonSoul_RefineWindow_GetOpener())
    				ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°*È*âÀ» ¿¬ »óÅ¿¡¼*´Â ¾ÆÀÌÅÛÀ» ¿Å±æ ¼ö ¾ø½À´Ï´Ù."));
    			return false;
    		}
    
    		if (IsDead())
    			return false;
    		if (!IsValidItemPosition(Cell) || !(item = GetItem(Cell)))
    			return false;
    		if (item->IsExchanging())
    			return false;
    		if (true == item->isLocked())
    			return false;
    		if (quest::CQuestManager::instance().GetPCForce(GetPlayerID())->IsRunning() == true)
    			return false;
    		if (item->GetCount() <= 0)
    			return false;
    
    		if (bCount == 0 || bCount > item->GetCount())
    			bCount = item->GetCount();
    
    		SyncQuickslot(QUICKSLOT_TYPE_ITEM, Cell.cell, 255);
    
    		if (bCount == item->GetCount())
    		{
    			item->RemoveFromCharacter();
    		}
    		else
    		{
    			if (bCount == 0)
    			{
    				if (test_server)
    					sys_log(0, "[DROP_ITEM] drop item count == 0");
    				return false;
    			}
    
    			item->SetCount(item->GetCount() - bCount);
    			ITEM_MANAGER::instance().FlushDelayedSave(item);
    		}
    
    		ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You destroyed: %d x %s."), bCount, item->GetName());
    		return true;
    	}
    #endif

    Server/input.h

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    		void		ItemDestroy(LPCHARACTER ch, const char* data);
    #endif

    Server/char.h

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    		bool			DestroyItem(TItemPos Cell, BYTE bCount = 0);
    #endif

    Server/input_main.cpp

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    		case HEADER_CG_ITEM_DESTROY:
    			if (!ch->IsObserverMode())
    				ItemDestroy(ch, c_pData);
    			break;
    #endif

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	void CInputMain::ItemDestroy(LPCHARACTER ch, const char* data)
    	{
    		struct command_item_destroy* pinfo = (struct command_item_destroy*)data;
    		if (ch)
    			ch->DestroyItem(pinfo->Cell, pinfo->count);
    	}
    #endif

    Server/packet.h

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	HEADER_CG_ITEM_DESTROY			= 21,
    #endif

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	typedef struct command_item_destroy
    	{
    		BYTE		header;
    		TItemPos	Cell;
    		BYTE		count;
    	} TPacketCGItemDestroy;
    #endif

    Server/packet_info.cpp

    Add :

    #ifdef M2_FEATURE_DESTROY_ITEM
    	Set(HEADER_CG_ITEM_DESTROY, sizeof(TPacketCGItemDestroy), "ItemDestroy", true);
    #endif

    Client/game.py

    Add :

    	if app.M2_FEATURE_DESTROY_ITEM:
    		def __SendDestroyItemPacket(self, itemVNum, itemCount, itemInvenType = player.INVENTORY):
    			if uiPrivateShopBuilder.IsBuildingPrivateShop():
    				chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.DROP_ITEM_FAILURE_PRIVATE_SHOP)
    				return
    			net.SendItemDestroyPacket(itemInvenType, itemVNum, itemCount)
    			return

    Add :

    	if app.M2_FEATURE_DESTROY_ITEM:
    		def RequestDestroyItem(self, answer):
    			if not self.itemDropQuestionDialog:
    				return
    
    			if answer:
    				## Question Text
    				questionText = "Are you really sure?"
    
    				## Dialog
    				itemDropQuestionDialog2 = uiCommon.QuestionDialog()
    				itemDropQuestionDialog2.SetText(questionText)
    				itemDropQuestionDialog2.SetAcceptEvent(lambda arg=True: self.RequestDestroyItemConfirm(arg))
    				itemDropQuestionDialog2.SetCancelEvent(lambda arg=False: self.RequestDestroyItemConfirm(arg))
    				itemDropQuestionDialog2.Open()
    				itemDropQuestionDialog2.dropType = self.itemDropQuestionDialog.dropType
    				itemDropQuestionDialog2.dropNumber = self.itemDropQuestionDialog.dropNumber
    				itemDropQuestionDialog2.dropCount = self.itemDropQuestionDialog.dropCount
    				self.itemDropQuestionDialog2 = itemDropQuestionDialog2
    
    			self.itemDropQuestionDialog.Close()
    			self.itemDropQuestionDialog = None
    
    			constInfo.SET_ITEM_QUESTION_DIALOG_STATUS(0)
    
    		def RequestDestroyItemConfirm(self, answer):
    			if not self.itemDropQuestionDialog2:
    				return
    
    			if answer:
    				dropType = self.itemDropQuestionDialog2.dropType
    				dropNumber = self.itemDropQuestionDialog2.dropNumber
    				dropCount = self.itemDropQuestionDialog2.dropCount
    
    				if player.SLOT_TYPE_INVENTORY == dropType:
    					if dropNumber == player.ITEM_MONEY:
    						return
    					else:
    						self.__SendDestroyItemPacket(dropNumber, dropCount)
    				elif player.SLOT_TYPE_DRAGON_SOUL_INVENTORY == dropType:
    					self.__SendDestroyItemPacket(dropNumber, dropCount, player.DRAGON_SOUL_INVENTORY)
    
    			self.itemDropQuestionDialog2.Close()
    			self.itemDropQuestionDialog2 = None
    
    			constInfo.SET_ITEM_QUESTION_DIALOG_STATUS(0)

    Full __DropItem :

    	def __DropItem(self, attachedType, attachedItemIndex, attachedItemSlotPos, attachedItemCount):
    		# PRIVATESHOP_DISABLE_ITEM_DROP - 개인상점 열고 있는 동안 아이템 버림 방지
    		if uiPrivateShopBuilder.IsBuildingPrivateShop():			
    			chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.DROP_ITEM_FAILURE_PRIVATE_SHOP)
    			return
    		# END_OF_PRIVATESHOP_DISABLE_ITEM_DROP
    		
    		if player.SLOT_TYPE_INVENTORY == attachedType and player.IsEquipmentSlot(attachedItemSlotPos):
    			self.stream.popupWindow.Close()
    			self.stream.popupWindow.Open(localeInfo.DROP_ITEM_FAILURE_EQUIP_ITEM, 0, localeInfo.UI_OK)
    
    		else:
    			if player.SLOT_TYPE_INVENTORY == attachedType:
    				dropItemIndex = player.GetItemIndex(attachedItemSlotPos)
    
    				item.SelectItem(dropItemIndex)
    				dropItemName = item.GetItemName()
    
    				## Question Text
    				questionText = localeInfo.HOW_MANY_ITEM_DO_YOU_DROP(dropItemName, attachedItemCount)
    
    				## Dialog
    				if app.M2_FEATURE_DESTROY_ITEM:
    					itemDropQuestionDialog = uiCommon.QuestionDialogItem()
    				else:
    					itemDropQuestionDialog = uiCommon.QuestionDialog()
    
    				itemDropQuestionDialog.SetText(questionText)
    				itemDropQuestionDialog.SetAcceptEvent(lambda arg=True: self.RequestDropItem(arg))
    
    				if app.M2_FEATURE_DESTROY_ITEM:
    					itemDropQuestionDialog.SetDestroyEvent(lambda arg=TRUE: self.RequestDestroyItem(arg))
    
    				itemDropQuestionDialog.SetCancelEvent(lambda arg=False: self.RequestDropItem(arg))
    				itemDropQuestionDialog.Open()
    				itemDropQuestionDialog.dropType = attachedType
    				itemDropQuestionDialog.dropNumber = attachedItemSlotPos
    				itemDropQuestionDialog.dropCount = attachedItemCount
    				self.itemDropQuestionDialog = itemDropQuestionDialog
    
    				constInfo.SET_ITEM_QUESTION_DIALOG_STATUS(1)
    			elif player.SLOT_TYPE_DRAGON_SOUL_INVENTORY == attachedType:
    				dropItemIndex = player.GetItemIndex(player.DRAGON_SOUL_INVENTORY, attachedItemSlotPos)
    
    				item.SelectItem(dropItemIndex)
    				dropItemName = item.GetItemName()
    
    				## Question Text
    				questionText = localeInfo.HOW_MANY_ITEM_DO_YOU_DROP(dropItemName, attachedItemCount)
    
    				## Dialog
    				if app.M2_FEATURE_DESTROY_ITEM:
    					itemDropQuestionDialog = uiCommon.QuestionDialogItem()
    				else:
    					itemDropQuestionDialog = uiCommon.QuestionDialog()
    
    				itemDropQuestionDialog.SetText(questionText)
    				itemDropQuestionDialog.SetAcceptEvent(lambda arg=True: self.RequestDropItem(arg))
    
    				if app.M2_FEATURE_DESTROY_ITEM:
    					itemDropQuestionDialog.SetDestroyEvent(lambda arg=TRUE: self.RequestDestroyItem(arg))
    
    				itemDropQuestionDialog.SetCancelEvent(lambda arg=False: self.RequestDropItem(arg))
    				itemDropQuestionDialog.Open()
    				itemDropQuestionDialog.dropType = attachedType
    				itemDropQuestionDialog.dropNumber = attachedItemSlotPos
    				itemDropQuestionDialog.dropCount = attachedItemCount
    				self.itemDropQuestionDialog = itemDropQuestionDialog
    
    				constInfo.SET_ITEM_QUESTION_DIALOG_STATUS(1)

     

     

     

    • Metin2 Dev 4
    • Love 2
  6. 5 minutes ago, ReFresh said:

    Two more methods:

    char_item.cpp:

      Hide contents
    bool CHARACTER::CanHandleItem(bool bSkipCheckRefine, bool bSkipObserver)
    {
    	if (GetMyShop() || GetShop() || GetExchange())
    		return false;
    }

    uiinventory.py:

      Hide contents
    def __SendUseItemToItemPacket(self, srcSlotPos, dstSlotPos):
    		if uiPrivateShopBuilder.IsBuildingPrivateShop() or exchange.isTrading() or shop.IsOpen():
    			chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.USE_ITEM_FAILURE_PRIVATE_SHOP)
    			return
    
    		net.SendItemUseToItemPacket(srcSlotPos, dstSlotPos)
    
    	def __SendUseItemPacket(self, slotPos):
    		if uiPrivateShopBuilder.IsBuildingPrivateShop() or exchange.isTrading() or shop.IsOpen():
    			chat.AppendChat(chat.CHAT_TYPE_INFO, localeInfo.USE_ITEM_FAILURE_PRIVATE_SHOP)
    			return
    
    		net.SendItemUsePacket(slotPos)

     

    I had suggested the first method, then deleted my answer. With the first method, I can no longer sell items to an NPC.

    • Good 1
  7. 52 minutes ago, ReFresh said:

    @ASIKOONice idea! Would be nice, if you can do little improvement to that: 

    When you click on do_emotion_allow button, allowed emotions will be set to 1 for that character and after the teleport or relog it will be resetted to 0. It will prevent the spamming ChatPacket. I know you did a prevention for that already, but solution from my idea should be better.

    And you can add a chat packet information for that player who sent a request to allow emotions:

      Hide contents
    	LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(val);
    	
    	if (ch)
    	{
    		ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Emotions from %s were allowed."), tch->GetName());
    	}
    	
    	if (tch)
    	{
    		tch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s wants to share emotions with you."), ch->GetName());
    	}

     

    I did this, I think we can do even more optimized.
    I tried :

    ACMD(do_emotion_allow)
    {
    	if ( ch->GetArena() )
    	{
    		ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("´ë·ÃÀå¿¡¼­ »ç¿ëÇÏ½Ç ¼ö ¾ø½À´Ï´Ù."));
    		return;
    	}
    
    	char arg1[256];
    	one_argument(argument, arg1, sizeof(arg1));
    
    	if (!*arg1)
    		return;
    
    	uint32_t	val = 0; str_to_number(val, arg1);
    
    #ifdef M2_FEATURE_NOTICE_EMOTION
    	LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(val);
    
    	if (tch)
    	{
    
    		bool bFrom = !(s_emotion_set.find(std::make_pair(ch->GetVID(), val)) == s_emotion_set.end());
    		bool bTo = !(s_emotion_set.find(std::make_pair(val, ch->GetVID())) == s_emotion_set.end());
    
    		if (bFrom && bTo)
    		{
    			ch->ChatPacket(CHAT_TYPE_INFO, "You are currently sharing emotions with your partner! <3");
    
    			return;
    		}
    
    		if (!bFrom && bTo)
    		{
    			s_emotion_set.insert(std::make_pair(ch->GetVID(), val));
    
    			ch->ChatPacket(CHAT_TYPE_INFO, "You allowed emotions with %s.", tch->GetName());
    			tch->ChatPacket(CHAT_TYPE_INFO, "%s allowed to share emotions.", ch->GetName());
    
    			return;
    		}
    
    		if (bFrom)
    		{
    			ch->ChatPacket(CHAT_TYPE_INFO, "You have already asked to share emotions with %s...", tch->GetName());
    			ch->ChatPacket(CHAT_TYPE_INFO, "Don't anger your partner and be patient!");
    
    			return;
    		}
    		else
    		{
    			s_emotion_set.insert(std::make_pair(ch->GetVID(), val));
    
    			ch->ChatPacket(CHAT_TYPE_INFO, "You asked to share emotions with %s.", tch->GetName());
    			tch->ChatPacket(CHAT_TYPE_INFO, "%s requested to share emotions with you.", ch->GetName());
    
    			return;
    		}
    	}
    #else
    	s_emotion_set.insert(std::make_pair(ch->GetVID(), val));
    #endif
    }

     

    • Metin2 Dev 3
    • Good 1
    • Love 1
  8. C++ Version

    In: cmd_emotion.cpp (game source)
    Add:

    #include "config.h"

    Find:

    ACMD(do_emotion_allow)
    {
    	[...]
    }

    Replace like this:

    ACMD(do_emotion_allow)
    {
    	if ( ch->GetArena() )
    	{
    		ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("´ë·ÃÀå¿¡¼­ »ç¿ëÇÏ½Ç ¼ö ¾ø½À´Ï´Ù."));
    		return;
    	}
    
    #ifdef M2_FEATURE_NOTICE_EMOTION
    	if (thecore_heart->pulse - (int32_t)ch->GetLastShoutPulse() < passes_per_sec * 15)
    	{
    		ch->ChatPacket(CHAT_TYPE_INFO, "Please, stop spam!");
    		return;
    	}
    
    	ch->SetLastShoutPulse(thecore_heart->pulse);
    #endif
    
    	char arg1[256];
    	one_argument(argument, arg1, sizeof(arg1));
    
    	if (!*arg1)
    		return;
    
    	uint32_t	val = 0; str_to_number(val, arg1);
    	s_emotion_set.insert(std::make_pair(ch->GetVID(), val));
    
    #ifdef M2_FEATURE_NOTICE_EMOTION
    	LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(val);
    	if (tch)
    	{
    		tch->ChatPacket(CHAT_TYPE_INFO, "%s requested the use of emotions with you %s", ch->GetName(), tch->GetName());
    	}
    #endif
    }

    And add define in your service.h or similar:

    #define M2_FEATURE_NOTICE_EMOTION
    • Metin2 Dev 1
    • Good 1
  9. 9 minutes ago, WeedHex said:

    Ehhhm sorry I'm not LUA addict ahaha.

    I did with c++ an other way (based on what I need to check) because happened some guys exploit the begin_other_pc_block in some server. (With change channel and shits like that)

    Of course if is only for level you can check it again in the dungeon and kick him out, but better to be careful in big servers about these things.

     

    PS. WTF only I see my messages x2? 

    Known bug, sorry..

    • Good 1
  10. Migration to a new server completed...
    DNS zone update in progress...

    • PHP 7.4.26 => PHP 8.1.7
    • MariaDB 10.5.12 => MariaDB 10.5.15
    • IPS 4.6.12.1 (Stable Build) => IPS 4.7.0 (Dev Build)
    • Websites Server ⬇️
      • metin2.dev
      • metin2dev.org
      • funky-emu.net

     

    Cache is rebuilding, all maintenance tasks are running...

    • Metin2 Dev 2
    • kekw 1
×
×
  • 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.