Jump to content

Shogun

Premium
  • Posts

    1361
  • Joined

  • Days Won

    77
  • Feedback

    0%

Posts posted by Shogun

  1. M2 Download Center

    This is the hidden content, please
    ( Internal )

    So after 5 years I finally decided to make a map from scratch, which became the new map 1 for romanian players in WoM2: the Deunsang Citadel.

     

    Spoiler

    0817237uTvbab.png.2c066ded1086be800d5e12
    081723fI4Kaab.png.a7bb239546c1719c958909
    081723QhGqfab.png.2371df532f71c8c85a2475

     

    I am also releasing most of the trees and shrubs I used, these are from Oblivion and I did already release them before (and many people used them in their maps) but I reworked both the lighting and the textures, especially of the trees, and fixed a couple that were not working before.

     

    This is the hidden content, please
    !JxklI1qYBUnzfq-DRcF5ab0mvS08ORbfl1D1oGSIv5I

    • Metin2 Dev 27
    • Eyes 1
    • Dislove 2
    • Not Good 1
    • Think 1
    • Good 10
    • Love 3
    • Love 38
  2.  

    hace 6 horas, ReFresh dijo:

    @Cunoo I can do much better things around graphic details but I don't need it and I don't have a time for it. I'm glad too when someone help me or post a free stuff. :) 

    Well nobody cares? This is how they were supposed to look, that's why the field in the database is called specular, because it´s supposed to change the reflection not just the brightness as it was. It's explained in this post from 4 years ago, in the second part:

    https://www.elitepvpers.com/forum/metin2-pserver-guides-strategies/3514142-tutorial-save-dds-photoshop-reflection-effect.html

    Now go whine somewhere else.

    • Metin2 Dev 2
    • Love 5
  3. Today I'm going to explain how to add and modify the different sounds that exist in the game.

    First of all we have the soundtrack; the music that is played in each map or when we choose it from the music menu. This is pretty straightforward as we just have to copy mp3 files to the bgm folder and they will be read automatically.

    In order to add the mp3 file as default sound on a map, you would edit locale/whatever/settings.lua and find lines looking like this

    add_bgm_info(125, "chasing_dragon.mp3", 0.5)

    Where the first value is the map index, second the filename and third the volume. Pretty straightforward.

    The next option the game offers us in the accoustic department is adding a sound to a motion, such as a skill or an emotion. In order to do this, we just need to find the msa file which we want to add a sound to. We will go to the folder of the mob, npc or character in question, find the motion we want through the motlist (if it's not a character), and then; create the respective folder under sound if it doesn't exist. For example, for adding a sound to the motion npc/bakchon/01.msa we would make the folder sound/npc/backchon/ and in it a text file name 01.mss with this format:

     

    ScriptType        CharacterSoundInformation
    
    SoundDataCount    2
    SoundData00       0.396000 "sound/monster/ice_snow_golem/drop_1.wav"
    SoundData01       0.000000 "sound/monster/ice_snow_golem/fall_1.wav"

    SoundDataCount: number of sounds

    SoundData00 etc is just used to list the sounds in order and finally the number represents the time, in seconds, that the sound will wait to be played once the motion starts. Of course if the time is higher than the motion duration, the sound is never going to work.

    The third option for adding sounds is doing it in the msa files themselves through MOTION_EVENT_TYPE_SOUND. I'm not going to comment this because it's never used by YMir and the mss methos is just easier.

    Finally, we can add sounds to an specific place in a map, such as water running under a bridge. To do this, we have to create a .pra file in the property folder/pack with the following information:

    YPRT
    778119171
    ambiencesoundvector        "sound/ambience/water_underbridge.wav"
    propertyname        "water_underbridge"
    propertytype        "Ambience"
    maxvolumeareapercentage        "0.300000"
    playinterval        "0.000000"
    playintervalvariation        "0.000000"
    playtype        "LOOP"

    YPRT: just an identifier so the game knows its a property file (Ymir PRoperTy)

    The number is supposed to be the CRC of the file, but you can use whatever you want as long as it's unique. If you change this number later,  the asset will disappear from the maps where you used it so be careful.

    • ambiencesoundvector: filename of a WAV or MP3 file
    • propertyname: just a name to identify it, can be anything.
    • propertytype: in this case Ambience and be careful with case, it's an uppercase A at the start!
    • maxvolumeareapercentage: which percentage (0 to 1) of the radius around the placement of the sound is played at 100% volume. I would set this to 1 for non-looping sounds as they only play once when you enter the defined area and won't play again till you leave and re-enter it.
    • playinterval: how frequently a sound of type STEP plays
    • playintervalvariation: random variation on the previous interval.
    • playtype: ONCE, STEP or LOOP

    Once in World Editor, we can add our sounds as any other object; except we will set their Size, or the radius around the placement where it will be played, with the AreaAmbienceSize control in WE. If maxvolumeareasize is less than 1, the sound will get quieter from that % of the radius and end up being totally silent at the edge of the total radius.

    As I mentioned, all the sounds in the game can be either MP3 or WAV. A comment about WAV files. Most WAV files we can find on the internet will not work with Metin2 straight away. We can use MP3 instead, but we are adding unnecessary overhead to the game, so if you want to use WAV files in Metin here's how.

    - Download and install the free Audacity Sample Editor. https://www.audacityteam.org/download/windows/

    - Open the original WAV file with it. You may need to press CTRL+A to select the whole sample.

    - Metin2 doesn't play stereo WAVs so if your WAV is stereo head to the Track menu and choose > Mix > Mix stereo down to mono.

    - Choose Resample... in the same menu and then 22050

    - In the top left select "Project Rate" and change it to 22050

    - Finally go to the File menu and click on Export and then WAV. Choose 16 bit PCM as format and done.

    • Metin2 Dev 4
    • Angry 1
    • Good 1
    • Love 21
  4. As we work with maps we accumulate a large number of unused textures which end up making the client / pack downloads for our server bigger. For this reason I made this little python 2.7 script.

    It will read all the textureset files and the texture paths on it and copy to textureset_release/ only the textures that are actually being used by your maps, as listed in Settings.txt

    The folder where the script looks for Settings.txt files recursively is "maps/", change it at the start of the code if yours is different. Likewise, it will look for "textureset/" and "terrainmaps/", and create "textureset_release/". No files will be deleted.

    Disclaimer: The code is very ugly, I actually have no idea of python, I made this script looking at docs and based on my knowledge of other languages. If you actually know python I suggest you don't look at it to avoid hurting your eyes.

     

    import os
    import re
    import string
    import shutil
    import sys
    
    ct = 0
    usedimg = []
    usedsets = []
    list = []
    mapfolder = 'maps/'
    
    class cd:
        """Context manager for changing the current working directory"""
        def __init__(self, newPath):
            self.newPath = os.path.expanduser(newPath)
    
        def __enter__(self):
            self.savedPath = os.getcwd()
            os.chdir(self.newPath)
    
        def __exit__(self, etype, value, traceback):
            os.chdir(self.savedPath)
    
    def cleanValue(val):
    	val = val.replace('\\', '/')
    	val = val.strip(' \t\n"')
    	val = val.lower()
    	return val
    
    def copyFile(src, dest):
        try:
            shutil.copy(src, dest)
        # eg. src and dest are the same file
        except shutil.Error as e:
            print('Error: %s' % e)
        # eg. source or destination doesn't exist
        except IOError as e:
            print('Error: %s' % e.strerror)
    
    # Read the tab-separated value of a parameter "param" in all files named "fname" (can be an extension) in folder "folder"
    
    def SaveParams(param,fname,folder,list):
    	for path, subdirs, files in os.walk(folder):
    		for filename in files:
    			if filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname)):
    				f = os.path.join(path, filename)
    				with open(f, "rt") as current:
    					for line in current:
    						lcline = line.lower() 
    						lcparam = param.lower()
    						if lcparam in lcline:
    							# strip tabs and split values
    							value = line.rstrip('\t\n')
    							# get parameter value
    							list.append(value)
    
    # Read a value with the order number "order" within a parameter block "block" in all files named "fname" (can be an extension) in folder "folder" which are also in list "compare"
    
    def SaveParamsFromBlock(block,order,fname,folder,list,compare):
    	for path, subdirs, files in os.walk(folder):
    		for filename in files:
    			if filename in compare and (filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname))):
    				countblock = -1
    				f = os.path.join(path, filename)
    				with open(f, "rt") as current:
    					for line in current:
    						lcline = line.lower() 
    						lcblock = block.lower()
    						if countblock == order:
    							list.append(line)							
    							countblock = -1
    						elif lcline.startswith(lcblock):
    							countblock = 0
    						elif countblock >= 0:
    							countblock = countblock + 1
    
    # move to the client data folder
    
    with cd('..\client\data'):
    
    	try:
    		os.makedirs('terrainmaps_release')
    	except:
    		shutil.rmtree('terrainmaps_release')
    		os.makedirs('terrainmaps_release')
    
    	print "This script copies to terrainmaps_release only the textures which are actually listed in textureset files."
    	print "The folder is emptied on each run. make_archive.py uses this folder as source for making the terrainmaps pack."
    	print "This script is written to be run from the tools repo copy and assumes the client repo copy to be in the same base directory as tools"
    	print ""
    	select = raw_input("Press any key to start, e to exit")
    	if str(select) == "e":
    		sys.exit()
    	
    	# Get all the texturesets used in our maps
    
    	SaveParams('TextureSet','Setting.txt','maps',usedsets)
    
    	# Extract the filename part of the used TextureSet paths and write it back to the list
     
    	for idx,val in enumerate(usedsets):
    		val = cleanValue(val)
    		parts = re.split('/', val.lower())
    		# check its actually a terrainmaps path
    		usedsets[idx] = parts[-1]
    
    	# Fetch a list of the textures used in the sets used
    
    	SaveParamsFromBlock('Start Texture',0,'.txt','textureset',usedimg,usedsets)
    
    	# Copy the textures used in textureset_release
    
    	for idx,val in enumerate(usedimg):
    		# check its actually a terrainmaps path
    		if  "terrainmaps" in val:
    			val = cleanValue(val)
    			val = val[len('d:/ymir work/terrainmaps/'):]
    			usedimg[idx] = val.lower()
    			srcPath = 'terrainmaps/' + usedimg[idx]
    			destPath = 'terrainmaps_release/' + usedimg[idx]
    			print "Copy " + srcPath + " to " + destPath
    			if not os.path.isdir(os.path.dirname(destPath)):
    				os.makedirs(os.path.dirname(destPath))
    			copyFile(srcPath, destPath)
    			ct = ct + 1
    	print "Total " + str(ct) + " textures copied in terrainmaps_release"
    	raw_input("Press any key to exit")

    As a bonus another python 2.7 script used to create the property/list file with all your prb, pre. Assumes a property/ folder at the location where you run it.

     

    import os
    import math
    
    count = 0
    extensions = ('prb','prt','prd','pre','pra')
    with open("property/list", "w") as a:
        for path, subdirs, files in os.walk(r'property'):
           	for filename in files:
            	f = os.path.join(path, filename)
            	if filename != "list" and filename !="reserve":
             		extension = filename.split ('.')[-1]
             		if (extension in extensions): 
                			a.write(str(f) + '\n')
             		else:
             			Print ("Strange file: " + f)
             		count = count + 1
    print 'Total: ' + str(count) + ' files listed on property/list!'
    
    raw_input("Press any key to exit")

     

    And finally another script to copy all your msa and motlist.txt files to a server/data folder that you can upload later to your server. It will only copy when files are different or not existing at the destination. It assumes a ../client/data/npc (and so on) and ../server/data/monster etc. structure, feel free to edit the paths in the scripts to your needs.

     

    import os
    import shutil
    from itertools import chain
    import filecmp
    
    pathList = []
    count = 0
    
    def copyFile(src, dest):
        try:
            shutil.copy(src, dest)
            return True
        # eg. src and dest are the same file
        except shutil.Error as e:
            print('Error: %s' % e)
        # eg. source or destination doesn't exist
        except IOError as e:
            print('Error: %s' % e.strerror)
    
    print "This script moves all the .msa and motlist.txt files from pc monster and npc client folders to the appropiate server folders, creating them if necessary."
    paths = ('../client/data/monster/', '../client/data/monster2/', '../client/data/npc/', '../client/data/npc2/', '../client/data/pc/', '../client/data/pc2/')
    for path, dirs, files in chain.from_iterable(os.walk(path) for path in paths):
    	for filename in files:
    		if filename.endswith('.msa') or filename.endswith('.txt'):
    			realpath = path.replace('\\', '/')
    			cfolder = os.path.split(realpath)[1]
    			gfolder = 'monster'
    			if ('/pc/' in realpath):
    				gfolder = 'pc/' + realpath.split('/')[4]
    			elif ('/pc2/' in realpath):
    				gfolder = 'pc2/' + realpath.split('/')[4]
    			else:
    				# Check for duplicated non-pc folders
    				existingpath = next((s for s in pathList if ('/' + cfolder) in s), None)
    				if existingpath and existingpath.endswith(cfolder):
    					if realpath != existingpath:
    						print("Warning: duplicate folders " + realpath + " and " + existingpath + "!")
    						pathList.remove(existingpath)
    						break
    					elif path not in pathList:
    						pathList.append(realpath)
    				else:
    					pathList.append(realpath)
    				
    			spath = realpath  + '/' + filename
    
    			dpath = '../server/data/' + gfolder + '/' + cfolder
    			# Create destination folder if not existing
    			if not os.path.isdir(dpath):
    				os.makedirs(dpath)
    			dpath = dpath + '/' + filename
    			# Copy file if destination is not existing or different
    			if not os.path.exists(dpath) or not filecmp.cmp(spath,dpath):
    				if copyFile(spath, dpath):
    					print "Copied " + spath + " to " + dpath
    					count = count + 1
    
    print "Finished copying " + str(count) + " files!"
    raw_input("Press any key to exit")

    How to use: install python 2.7 anywhere on your hd (C:\Python27 for example), add this path to the system path, and save this code in a file named something.py, then run it by doubleclick

    Remember to change directory to wherever you have your client files.

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