Jump to content

Reached

Active+ Member
  • Posts

    21
  • Joined

  • Last visited

  • Feedback

    0%

Posts posted by Reached

  1. Hello, this is a script that will help you fill in the empty spaces of the folder section of the mount caused by missing additions in mob_proto.

    import os
    import chardet
    
    ITEM_PROTO_PATH = "item_proto.txt"
    MOB_PROTO_PATH = "mob_proto.txt"
    NPC_LIST_PATH = "npclist.txt"
    LOG_FILE_PATH = "no_folder_mounts.txt"
    MOB_NAMES_FILE_PATH = "mob_names.txt"
    MOUNT_WITH_FOLDERS = "mount_with_folders.txt"
    SERVER_DATA_FOLDER = "C:\\git\\CarbonSFv2\\server\\srv1\\share\\data\\monster"
    SERVER_MISSING_FOLDERS = "server_missing_folders.txt"
    
    MOUNT_TYPE = "ITEM_COSTUME"
    MOUNT_SUBTYPE = "COSTUME_MOUNT"
    
    
    MOUNT_LIST = []
    MOUNT_WITH_NO_FOLDER = []
    
    
    ITEM_TYPE = 2
    ITEM_SUBTYPE = 3
    ITEM_MOUNT_VALUE = 28
    
    MOB_PROTO_MOUNT_VNUM = 0
    MOB_PROTO_FOLDER_INDEX = 12
    
    
    def process_file(file_path):
        with open(file_path, 'rb') as file:
            rawdata = file.read()
            encoding = chardet.detect(rawdata)['encoding']
        
        #convert to utf-8 if not already
        if encoding and encoding.lower() != 'utf-8':
            with open(file_path, 'r', encoding=encoding) as file:
                content = file.read()
            with open(file_path, 'w', encoding='utf-8') as file:
                file.write(content)
    
    def checkCostumeMount(file_path):
        with open(file_path, 'r') as file:
            for line in file:
                if not line.strip():
                    continue
                split = line.split('\t')
                try:
                    if split[ITEM_TYPE] == MOUNT_TYPE and split[ITEM_SUBTYPE] == MOUNT_SUBTYPE:
                        MOUNT_LIST.append(split[ITEM_MOUNT_VALUE])
                except IndexError:
                    print("Index Error on line: " + line)
    
    def checkMobLine(file_path):
        process_file(file_path)
        with open(file_path, 'r', encoding='utf-8') as file:
            try:
                for line in file:
                    if not line.strip():
                        continue
                        
                    split = line.split('\t')
                    try:
                        if split[MOB_PROTO_MOUNT_VNUM] in MOUNT_LIST and split[MOB_PROTO_FOLDER_INDEX] == "":
                            print("Mount with no folder: " + split[MOB_PROTO_MOUNT_VNUM])
                            MOUNT_WITH_NO_FOLDER.append(split[MOB_PROTO_MOUNT_VNUM])
                    except IndexError:
                        print("Index Error on line: " + line)
            except UnicodeDecodeError:
                print("UnicodeDecodeError on line: " + line)
    
    def writeIntoFile(file_path, log_file_path):
        logFile = open(log_file_path, 'w')
        with open(file_path, 'r') as file:
            for line in file:
                if not line.strip():
                    continue
                split = line.split('\t')
                try:
                    if split[0] in MOUNT_WITH_NO_FOLDER:
                        logFile.write(line)
                except IndexError:
                    print("Index Error on line: " + line)
        logFile.close()
    
    def setFolder(file_path):
        mountWithFolders = open(MOUNT_WITH_FOLDERS, 'w')
        with open(file_path, 'r') as file:
            for line in file:
                if not line.strip():
                    continue
                    
                split = line.split('\t')
    
                try:
                    if split[0] in MOUNT_WITH_NO_FOLDER:
                        mountWithFolders.write(line)
                except IndexError:
                    print("Index Error on line: " + line)
        mountWithFolders.close()
    
    def checkFolderExist(folder_path):
        serverMissingFolders = open(SERVER_MISSING_FOLDERS, 'w')
        with open(MOUNT_WITH_FOLDERS, 'r') as file:
            for line in file:
                if not line.strip():
                    continue
                split = line.split('\t')
                folder = os.path.join(folder_path, split[1])
                if not os.path.exists(folder):
                    serverMissingFolders.write(folder + "\n")
                else:
                    print("Folder exists: " + folder)
        serverMissingFolders.close()
    
    
    
    def main():
        checkCostumeMount(ITEM_PROTO_PATH)
        checkMobLine(MOB_PROTO_PATH)
        writeIntoFile(MOB_NAMES_FILE_PATH, LOG_FILE_PATH)
        setFolder(NPC_LIST_PATH)
        checkFolderExist(SERVER_DATA_FOLDER)
    
    
    if __name__ == "__main__":
        main()

     

    Tutorial

    Spoiler

    In main.py

    ITEM_TYPE = 2
    ITEM_SUBTYPE = 3
    ITEM_MOUNT_VALUE = 28
    MOB_PROTO_MOUNT_VNUM = 0
    MOB_PROTO_FOLDER_INDEX = 12

    Configure the values in these sections according to your needs.
    For example item_proto:
    0->Vnum
    1->locale_name
    2->type
    If the mount gets its mob number from value, check which column it is in and replace it with ITEM_MOUNT_VALUE.
    Install the chardet package.

    pip install chardet

    Set the contents of the file like this:

    item_proto.txt
    mob_proto.txt
    mob_names.txt
    npclist.txt

    After setting the file like this;
    Run the script with Python.

    python .\main.py

     

    There are files for the vnums you need to complete in the mount_with_folder.txt file.
    You can complete the missing

    • Metin2 Dev 2
    • muscle 1
    • Love 3
  2. 6 hours ago, martysama0134 said:

    Another annoying issue is the repeated commands. This solves that issue:

    	def __PushLastSentenceStack(self, text):
    		global ENABLE_LAST_SENTENCE_STACK
    		if not ENABLE_LAST_SENTENCE_STACK:
    			return
    		if len(text) <= 0:
    			return
    		if text in chatStack: #remove duplicated elements and push the new one on top
    			chatStack.remove(text)
    		if len(chatStack) > LAST_SENTENCE_STACK_SIZE:
    			chatStack.pop(0)
    		chatStack.append(text)

     

    Thank you for your contribution.

  3. # Search
    ENABLE_CHAT_COMMAND = True
    
    # Add below 
    chatStack = []
    LAST_SENTENCE_STACK_SIZE = 32
    
    # Search
    def __PrevLastSentenceStack(self):
    
    # Change whole function
    
        def __PrevLastSentenceStack(self):
            if self.lastSentencePos < len(chatStack):
                self.lastSentencePos += 1
                lastSentence = chatStack[-self.lastSentencePos]
                self.SetText(lastSentence)
                self.SetEndPosition()
    
    
    # Search
    def __NextLastSentenceStack(self):
    
    # Change whole function
        def __NextLastSentenceStack(self):
            if self.lastSentencePos > 1:
                self.lastSentencePos -= 1
                lastSentence = chatStack[-self.lastSentencePos]
                self.SetText(lastSentence)
                self.SetEndPosition()
    
    # Search
    def __PushLastSentenceStack(self, text):
    
    # Change whole function.
        def __PushLastSentenceStack(self, text):
            global ENABLE_LAST_SENTENCE_STACK
            if not ENABLE_LAST_SENTENCE_STACK:
                return
            if len(text) <= 0:
                return
            if len(chatStack) > LAST_SENTENCE_STACK_SIZE:
                chatStack.pop(0)
            chatStack.append(text)

    It ensures that the saved message in the chat is not lost after teleporting.

    • Metin2 Dev 5
    • Good 2
    • Love 1
    • Love 2
  4. Thank you for sharing this tutorial, for the Set function error

     

    NetPacketHeaderMap.h

    //Add under the SPacketType struct
    
            TPacketType& createPacketType(int iSize = 0, bool bFlag = false)
    
            {
    
                return *(new TPacketType(iSize, bFlag));
    
            }

     

    and replace all the 

    //replace
    
        CNetworkPacketHeaderMap::TPacketType(
    
    //to this
    
        createPacketType(

     

    i solve it like this without any errors.

  5. This is the hidden content, please

    Alternative download links → 

    This is the hidden content, please

     

    Preview -> https://metin2.download/video/H3qHG80L4b7O2ZOrKZGsYswGL8izIeov/.mp4

    * When extracting a map from a files, it outputs all objects belonging to that map.

    * Rarely, some dds files are not put in the same folder with their gr2, so some objects may have problems with their textures. You can take the textures with the problem by hand by opening the gr2.

    * There is a video on how to do it in the Github README

    • Metin2 Dev 40
    • Eyes 1
    • Good 8
    • Love 3
    • Love 13
  6. 12 minutes ago, Syreldar said:

    A couple heads-up:

    1. You don't need to clear a server_timer inside its own trigger unless it's a server_loop_timer. Normal timers get cleared upon triggering.
    2. You could've just used another dungeon flag to get the state, instead of using c++ shenanigans. The immunity part is also easily achievable without any source-sided input.


     

    define FLOOR2_METINSTONE_VNUM 42069
    define FLOOR2_METINSTONE_SPAWN_LOCAL_X 333
    define FLOOR2_METINSTONE_SPAWN_LOCAL_Y 666
    define FLOOR2_METINSTONE_HP_THRESHOLD 50
    define FLOOR2_REGEN_PATH "example_dungeon/x.txt"
    define TIME_TO_WARP_NEXT 10
    
    function new_zodiac_notice(str)
        d.zodiac_notice_clear();
        d.zodiac_notice(str);
    end -- function
    
    when dungeon_warp_to_2floor.server_timer begin
        if (d.select(get_server_timer_arg())) then
            d.setf("level", 2);
            d.setf("2floor_metinstone_vid", d.spawn_mob(FLOOR2_METINSTONE_VNUM, FLOOR2_METINSTONE_SPAWN_LOCAL_X, FLOOR2_METINSTONE_SPAWN_LOCAL_Y));
            d.set_unique("2floor_metinstone", d.getf("2floor_metinstone_vid"));
            server_loop_timer("dungeon_2floor_control_metinstone_hp", 2, get_server_timer_arg())
            dungeon_name.new_zodiac_notice(string.format("<Floor 2 | Stage 1> Bring the Metinstone down to %d%% HPs", FLOOR2_METINSTONE_HP_THRESHOLD))
        end -- if
    end -- when
    
    when dungeon_2floor_control_metinstone_hp.server_timer begin
        if (d.select(get_server_timer_arg())) then
            if (d.unique_get_hp_perc("2floor_metinstone") <= FLOOR2_METINSTONE_HP_THRESHOLD) then
                clear_server_timer("dungeon_2floor_control_metinstone_hp", get_server_timer_arg());
                npc.set_vid_damage_mul(d.getf("2floor_metinstone_vid"), 0.0001);
                d.regen_file(FLOOR2_REGEN_PATH);
                server_loop_timer("dungeon_2floor_control_monster_count", 2, d.get_map_index());
                dungeon_name.new_zodiac_notice("<Floor 2 | Stage 2> Kill all the monsters")
            end -- if
        end -- if
    end -- when
    
    when dungeon_2floor_control_monster_count.server_timer begin
        if (d.select(get_server_timer_arg())) then
            if (d.count_monster() == 0) then
                clear_server_timer("dungeon_2floor_control_monster_count", get_server_timer_arg());
                npc.set_vid_damage_mul(d.getf("2floor_metinstone_vid"), 1.0);
                dungeon_name.new_zodiac_notice("<Floor 2 | Stage 3> Destroy the Metinstone")
            end -- if
        end -- if
    end -- if
    
    when kill with npc.get_race() == FLOOR2_METINSTONE_VNUM and d.getf("level") == 2 begin
        d.clear_regen();
        d.kill_all();
        d.kill_all(); -- If there are resurrecting units.
        
        dungeon_name.new_zodiac_notice(string.format("<Floor 2 Completed> Warping to next floor in %d seconds..", TIME_TO_WARP_NEXT))
        server_timer("dungeon_warp_to_3floor", TIME_TO_WARP_NEXT, d.get_map_index());
    end -- when
    
    when dungeon_warp_to_3floor.server_timer begin
        if (d.select(get_server_timer_arg())) then
            d.setf("level", 3);
            --
        end -- if
    end -- when

    This snippet behaves exactly the same and does not require any C++ input.

    Thank you for your suggestions and corrections. 

  7. This is the hidden content, please

    Alternative download links → 

    This is the hidden content, please

     

    I like Aeldra's Nilay Dungeon so I made it.

    Allows you to hit a metinstone up to 50% health and start a stage within the stage.

    The logic is simple, do this to bosses etc. You can also adapt it.

    I added an example dungeon quest usage, you can easily understand the logic.

     

    Spoiler

     

     

    • Metin2 Dev 74
    • Good 14
    • Love 2
    • Love 35
  8. 2 minutes ago, xTryhard said:

    ofc you set the weapon. in your code you use this

     

    item2->SetForceAttribute(idx, 72, value);

    as third parameter you use value.

    anyway this is the correct if statement :

     

    if (item2->GetAttributeValue(idx) >= 50 && item2->GetAttributeValue(idx) <= 200)
    	{
    		item2->SetForceAttribute(idx, 72, value);
    	}

     

    yes, i shared

  9. 9 hours ago, Xovarto said:

    It somehow is not adding the avg value.

    Even tho i have 55avg on weapon it says i need 50-150avg.

    Do i need to add further code beside the on u posted?

    Can you try like this

    				else if (item->GetVnum() == 75891)
    				{
    					if ((item2->GetType() == ITEM_WEAPON) && item2->HasAttr(72))
    					{
    						int16_t idx = item2->FindAttribute(72);
    						int32_t value = item2->GetAttributeValue(idx)+1;
    						if ((150 > item2->GetAttributeValue(idx)) && (item2->GetAttributeValue(idx) >= 50))
    						{
    							item2->SetForceAttribute(idx, 72, value);
    						}
    						else
    						{
    							ChatPacket(CHAT_TYPE_INFO, "You can only use this item which is between 80-200 avg.");
    							return false;
    						}
    					}
    					else
    					{
    						ChatPacket(CHAT_TYPE_INFO, "You can only use this item on weapons with average damage.");
    						return false;
    					}
    				}

     

    4 hours ago, xTryhard said:

    if you want just to increase a value from a bonus you dont have to change anything in item_proto 
    the bonus value is signed 16 bit that means you can have max. 32767  without change anything
     

    item2->SetForceAttribute(idx, 72, 32767);

    this function will do it

    also if you want to increase a value by 1 use the ++ increment operator instead of using +1  
     

    int32_t value = item2->GetAttributeValue(idx);
    ++value;


     

    Uhm no, I don't want to get the value 32767. I just want to increase an attribute type 150 by increasing value and this code does that. if you gonna do ++value, you'll increase by 1, and equals value to value+1. But you don't set it trough the weapon. You just declare a value by variable and you'll just increase value by 1.

  10. Today I will share with you something simple.

     

    char_item.cpp

    // Add in the USE_CHANGE_ATTRIBUTE case
    				else if (item->GetVnum() == 75891)
    				{
    					if ((item2->GetType() == ITEM_WEAPON) && item2->HasAttr(72))
    					{
    						int16_t idx = item2->FindAttribute(72);
    						int32_t value = item2->GetAttributeValue(idx)+1;
    						if ((150 > item2->GetAttributeValue(idx)) && (item2->GetAttributeValue(idx) >= 50))
    						{
    							item2->SetForceAttribute(idx, 72, value);
    						}
    						else
    						{
    							ChatPacket(CHAT_TYPE_INFO, "You can only use this item which is between 80-200 avg.");
    							return false;
    						}
    					}
    					else
    					{
    						ChatPacket(CHAT_TYPE_INFO, "You can only use this item on weapons with average damage.");
    						return false;
    					}
    				}

    item_names.txt

    75891	Efsun Arttırma

    item_proto.txt

    75891	a_c	ITEM_USE	USE_CHANGE_ATTRIBUTE	1	ANTI_DROP | ANTI_SELL	ITEM_STACKABLE | LOG	NONE	NONE	1000	0	0	0	0	LIMIT_NONE	0	LIMIT_NONE	0	APPLY_NONE	0	APPLY_NONE	0	APPLY_NONE	0	0	0	0	0	0	0	0	0	0

     

    https://metin2.download/picture/sZNM9Bsys7hT70MZWwro3N9Y7t95aQfR/.gif

    • Good 1
  11. On 2/15/2020 at 4:04 AM, blabla112 said:

    didnt work, did everything, i think i messed something up in the mysql... i dont know how to put them there

    It's work, after than adding codes open your mob_proto and for example

     

    1093 (Lucifer) Add the RaceFlag ATT_NEWATTRTYPE  

  12. Hello, i haven't seen a topic like this in the forum. I want to share it.

    Firs of all we create own attr type with RaceFlag (Maybe in the following days i'll show you how to without RaceFlag)

     

     

    Client Source:

     

    GameLib:

    ItemData.h

    Spoiler
    
    // Search: 
    	enum EApplyTypes
    	{
    // Add to Enum: 
    	APPLY_ATTBONUS_NEWATTRTYPE,

     

     

    UserInterface:

    PythonPlayerModule.cpp

    Spoiler
    
    // Search:
    	PyModule_AddIntConstant(poModule, "APPLY_ANTI_PENETRATE_PCT",	CItemData::APPLY_ANTI_PENETRATE_PCT );
    // Add:
    	PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_NEWATTRTYPE",	CItemData::APPLY_ATTBONUS_NEWATTRTYPE);

     

     

    Packet.h

    Spoiler
    
    // Search: 
      	enum EPointTypes
    	{
      	....
      	}
    // Add to Enum:
    	POINT_ATTBONUS_NEWATTRTYPE,

     

     

     

    Game Source:

     

    common:

    length.h

    Spoiler
    
    // Search: 
    	enum ERaceFlags
    	{
    // Add:
    	RACE_FLAG_ATT_NEWATTRTYPE	= (1 << /*Last number +1*/)
    
    // Search: 
    	enum EApplyTypes
        {
    // Add to Enum:
    	APPLY_ATTBONUS_NEWATTRTYPE,

     

     

    game:

    char.h

    Spoiler
    
    // Search: 
    	enum EPointTypes
    	{
    // Add to Enum:
    	POINT_ATTBONUS_NEWATTRTYPE,

     

     

    char.cpp

    Spoiler
    
    // Search: 
      	case POINT_RESIST_SHAMAN:
    // Add:
    	case POINT_ATTBONUS_NEWATTRTYPE:
    
    // Search: 
      	case APPLY_NORMAL_HIT_DAMAGE_BONUS:
    // Add:
    	case APPLY_ATTBONUS_NEWATTRTYPE:

     

     

    cmd_general.cpp

    Spoiler
    
    // Search:
    static const char* [...]
    
    	switch (apply_number)
    	{
    		// ICINDE BUL
    		case POINT_RESIST_SHAMAN:    
      			return LC_TEXT("¹«´ç°ø°Ý¿¡ %d%% ÀúÇ×");
    // Add:
    		case POINT_ATTBONUS_NEWATTRTYPE:    
      			return LC_TEXT("POINT_ATTBONUS_NEWATTRTYPE: %d%%");

     

     

    cmd_gm.cpp

    Spoiler
    
    // Search: 
    	tch->GetPoint(POINT_ATTBONUS_SHAMAN));
    // Add in do_state command:
    	ch->ChatPacket(CHAT_TYPE_INFO, "   NEWATTRTYPE:%3d%%",
    		tch->GetPoint(POINT_ATTBONUS_NEWATTRTYPE));

     

     

    constants.cpp

    Spoiler
    
    // Search: 
      	const TApplyInfo aApplyInfo[MAX_APPLY_NUM] =
    // Add in function:
    	{ POINT_ATTBONUS_NEWATTRTYPE,		},	// APPLY_ATTBONUS_NEWATTRTYPE,
    
    // Search: 
      TValueName c_aApplyTypeNames[] =
    // Search in this: 
      { NULL,        0            }
    // Add above:
    	{ "ATT_NEWATTRTYPE",    APPLY_ATTBONUS_NEWATTRTYPE    },

     

     

    battle.cpp

    Spoiler
    
    pkVictim (It meanings of defendor)
    pkAttacker is attacker 
    if we are adding Defence attr type from mobs we will add this func.
    if (pkAttacker->IsNPC() && pkVictim->IsPC())
    or we are adding attack attr type to mobs we will add this func.
    if (pkAttacker->IsPC() && pkVictim->IsNPC())
    
    Logic is this:
      
    //Search
    if (pkVictim->IsRaceFlag(RACE_FLAG_ANIMAL))
    	iAtk+= (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ANIMAL)) / 100;
    // Add:
    		else if (pkVictim->IsRaceFlag(RACE_FLAG_ATT_NEWATTRTYPE))
    			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_NEWATTRTYPE)) / 100;

     

     

    db:

    protoreader.cpp

    Spoiler
    
    // Search: 
    	string arApplyType[]
    // Add to the end:
    	"APPLY_ATTBONUS_NEWATTRTYPE",
    
    // Search: 
    	string arRaceFlag[]
    // Add to the end:
    	"ATT_NEWATTRTYPE"

     

     

     

    Tools:

    DumpProtoSource

     

    ItemCSVReader.cpp

    Spoiler
    
    // Search: 
          string arApplyType[]
    // Add to the end:
    	"APPLY_ATTBONUS_NEWATTRTYPE",
    
    // Search: 
    	string arRaceFlag[]
    // Add to the end:
    	"ATT_NEWATTRTYPE"

     

     

     

    Client

     

    root

    uitooltip.py

    Spoiler
    
    // Search: 
    	item.APPLY_ATTBONUS_DEVIL : localeInfo.TOOLTIP_APPLY_ATTBONUS_DEVIL,
    // Add:
    	item.APPLY_ATTBONUS_NEWATTRTYPE : localeInfo.TOOLTIP_APPLY_ATTBONUS_NEWATTRTYPE,

     

     

    locale

    locale_game.txt

    Spoiler
    
    // Add:
    TOOLTIP_APPLY_ATTBONUS_NEWATTRTYPE	Strong against to attr type you want xd	+%d%%	SA

     

     

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