Jump to content
Sign in to follow this  
Syfax

how to use deguix decompiler

Recommended Posts

Open user.lua and find it:

 

decompile_folder_bin('C:/Users/Synyster/Documents/Tales of Pirates/scripts/table',2) 

 

change to your folder, the number after mean the version of your client. After it open decompile.


lelouch_signature_by_vahntheknight-d4uafwj.png

Share this post


Link to post
Share on other sites

I thought his decompiler was coded in python. Also, syfax if you continue to post threads "title explain" without giving your errors, providing codes, explaining your problem,  you will not like it. Last warning to you. 

  • Like 2

kong.png

a2.png

Share this post


Link to post
Share on other sites
17 minutes ago, KONG said:

I thought his decompiler was coded in python. Also, syfax if you continue to post threads "title explain" without giving your errors, providing codes, explaining your problem,  you will not like it. Last warning to you. 

There is a version using lua

Share this post


Link to post
Share on other sites
8 hours ago, KONG said:

I thought his decompiler was coded in python. Also, syfax if you continue to post threads "title explain" without giving your errors, providing codes, explaining your problem,  you will not like it. Last warning to you. 

 

I'm glad that I'm not only one here who get pissed about it. You made my day @KONG :)

Share this post


Link to post
Share on other sites
3 hours ago, Syfax said:

I ask in the time needed so ,i asked this question because when i decompile TOP II Binnaries and open .txt files i see them weirdly written , (choosed it's version)

Thanks for the help

What Kong meant is that you should say that when creating the thread. How can one help you if he doesn't know what problem you have?

  • Like 2

Share this post


Link to post
Share on other sites

@Syfax do you can share it? We will see how to use it and write a guide.

 

@KONG, @Sultan Why not if title explains the question? There is expression 'Subject'


Share this post


Link to post
Share on other sites
1 hour ago, V3ct0r said:

@Syfax do you can share it? We will see how to use it and write a guide.

 

@KONG, @Sultan Why not if title explains the question? There is expression 'Subject'

its on my Archive called Deguix Decompiler (lua-jit)

https://mega.nz/#!WEIBTS5J!zBj0tvzfVUvuItzJn_YH38wx3mG0vHKR0owfZFzp2dU

Edit: i still prefer the pyton decompiler

Put this in txt and save it as .py (u must have python installed )

#o-----------------------------------------------------------------------------o
#| Bin decompiler v.1.6.2                                                      |
#(-----------------------------------------------------------------------------)
#| By deguix           / An Utility for TOP/PKO/KOP | Compatible w/ Python 3.3 |
#|                    ---------------------------------------------------------|
#|                                                                             |
#|   This script decompiles the .bin files for most game versions. If any      |
#| game version isn't supported, please let me know. Configuration section is  |
#| found at the bottom of the file.                                            |
#o-----------------------------------------------------------------------------o

import struct
from types import *
import subprocess

#---------------------------------------------

class top_tsv:
	name = ''
	file_name = ''
	list = []
	version = ''
	
	frombin_map = [('',{'v':0})]

	def __init__(self, file_name=0, version=0, encoding=0):
		if (file_name == 0):
			self.file_name = toptablefolder+self.__class__.__name__
		else:
			self.file_name = file_name

		if (version == 0):
			self.version = toptableversion
		else:
			self.version = version

		if (encoding == 0):
			self.encoding = 'gbk'
		else:
			self.encoding = encoding
		self.list = []
		self.frombin_map = [('',{'v':0})]
	
	def unencrypt(self):
		item = []

		#Load data
		file = open(self.file_name+'.bin', 'rb')
		data = bytearray(file.read())
		file.close()
		
		i = 0
		array_size = int(list(struct.unpack_from('<i',data[i:i+4]))[0])
		rdata = data[i:i+4]
		data = data[i+4:len(data)]
		m = 0
		k = 0
		l = len(data)//array_size

		#2.2 encryption
		if ((((((self.version >= 4) and (self.version <= 5)) or (self.version == 8)) and ((self.__class__.__name__ != 'magicsingleinfo') and (self.__class__.__name__ != 'magicgroupinfo') and (self.__class__.__name__ != 'resourceinfo') and (self.__class__.__name__ != 'terraininfo')))) or ((self.version >= 6) and (self.version <= 7))):
			newbytes = bytes.fromhex('98 9D 9F 68 E0 66 AB 70 E9 D1 E0 E0 CB DD D1 CB D5 CF')
		while(k<l):
			item = data[i:i+array_size]
			i = i+array_size
			if ((((((self.version >= 4) and (self.version <= 5)) or (self.version == 8)) and ((self.__class__.__name__ != 'magicsingleinfo') and (self.__class__.__name__ != 'magicgroupinfo') and (self.__class__.__name__ != 'resourceinfo') and (self.__class__.__name__ != 'terraininfo')))) or ((self.version >= 6) and (self.version <= 7))):
				for m,c in enumerate(item):
					j = m % len(newbytes)
					item[m] = ((item[m] - newbytes[j]) + 256) % 256
			rdata = rdata + item
			k = k + 1
		m = 0

		file = open(self.file_name+'-un.bin', 'wb')
		file.write(rdata)
		file.close()
	
	def load_bin_data(self):
		array = []
		item = []
		addresses = []

		#Load structure (calculate size)
		
		struct_type_map={
			"char":"c",
			"byte":"b",
			"ubyte":"B",
			"_bool":"?",
			"short":"h",
			"ushort":"H",
			"int":"i",
			"uint":"I",
			"long":"l",
			"ulong":"L",
			"quad":"q",
			"uquad":"Q",
			"float":"f",
			"double":"d",
			"str":"s",

			"color":"B",
			"rcolor":"B",
		}
		struct_vars = {'t':'','s':1,'l':1,'stp':1,'f':-1,'v':-1,'lpad':0,'rpad':0,'sa':-1,'sap':-1,'ea':-1,'eap':-1,'st':'','lm':0,'sm':0,'smb':0,'smea':0,'sv':0,'func':0}

		#initialize addresses
		struct_init_address = 0
		struct_limit_address = 0
		struct_marked_addresses = [0,0,0,0,0,0]
		struct_func_indexes = []
		
		for i, v in enumerate(list(zip(*self.frombin_map))[1]):
			struct_item = struct_vars.copy()
			struct_item.update(v)

			if struct_item['smb']>=1:
				struct_marked_addresses[struct_item['smb']] = struct_init_address
			if struct_item['lm']>=1:
				struct_init_address = struct_marked_addresses[struct_item['lm']]
			if struct_item['sm']>=1:
				struct_marked_addresses[struct_item['sm']] = struct_init_address

			if (type(struct_item['func']) == FunctionType):
				struct_func_indexes.append(i)
			elif (struct_item['v'] == -1):
				if type(struct_item['t']) == tuple:
					struct_item['s'] = len(struct_item['t'])
					struct_item['st'] = []
					for j,t in enumerate(struct_item['t']):
						struct_item['st'].append(struct_type_map[struct_item['t'][j]])
					struct_item['st'] = tuple(struct_item['st'])
					struct_item['s'] = len(struct_item['st'])
				else:
					struct_item['st'] = struct_type_map[struct_item['t']]
					if ((struct_item['t'] == 'color') or (struct_item['t'] == 'rcolor')):
						struct_item['s'] = 3

				struct_item['sa'] = struct_init_address
				struct_item['sap'] = struct_item['sa'] + struct_item['lpad']
				struct_item['ea'] = struct_item['sap']
				if type(struct_item['t']) == tuple:
					for j,t in enumerate(struct_item['t']):
						struct_item['ea'] = struct_item['ea'] + struct.calcsize(struct_item['st'][j]) * ((struct_item['stp'] * struct_item['l'])-(struct_item['stp']-1))
				else:
					struct_item['ea'] = struct_item['ea'] + struct.calcsize(struct_item['st']) * ((struct_item['s'] * struct_item['stp'] * struct_item['l'])-(struct_item['stp']-1))
				if struct_item['smea']>=1:
					struct_marked_addresses[struct_item['smea']] = struct_item['ea']
				struct_item['eap'] = struct_item['ea'] + struct_item['rpad']

				struct_init_address = struct_item['eap']
				if (struct_init_address > struct_limit_address):
					struct_limit_address = struct_init_address

				#print(struct_item)
			
			self.frombin_map[i] = (self.frombin_map[i][0],struct_item)

		struct_size = struct_limit_address
		
		#Load data
		file = open(self.file_name+'.bin', 'rb')
		data = bytearray(file.read())
		file.close()
		
		i = 0
		k = 0
		array_size = int(list(struct.unpack_from('<i',data[i:i+4]))[0])
		if array_size != struct_size:
			print(self.file_name+'.bin: Actual array size ('+str(array_size)+') doesn''t match structure size ('+str(struct_size)+')')
			raise 'Size error.'
		data = data[i+4:len(data)]
		m = 0
		k = 0
		l = len(data)//struct_size
		
		#2.2 encryption
		if ((((((self.version >= 4) and (self.version <= 5)) or (self.version == 8)) and ((self.__class__.__name__ != 'magicsingleinfo') and (self.__class__.__name__ != 'magicgroupinfo') and (self.__class__.__name__ != 'resourceinfo') and (self.__class__.__name__ != 'terraininfo')))) or ((self.version >= 6) and (self.version <= 7))):
			newbytes = bytes.fromhex('98 9D 9F 68 E0 66 AB 70 E9 D1 E0 E0 CB DD D1 CB D5 CF')
		while(k<l):
			item = data[i:i+struct_size]
			i = i+struct_size
			if ((((((self.version >= 4) and (self.version <= 5)) or (self.version == 8)) and ((self.__class__.__name__ != 'magicsingleinfo') and (self.__class__.__name__ != 'magicgroupinfo') and (self.__class__.__name__ != 'resourceinfo') and (self.__class__.__name__ != 'terraininfo')))) or ((self.version >= 6) and (self.version <= 7))):
				for m,c in enumerate(item):
					j = m % len(newbytes)
					item[m] = ((item[m] - newbytes[j]) + 256) % 256
			array.append(item)
			k = k + 1
		m = 0
		
		#Associate the data with the structure
		self.list = []
		self.list.append(list(zip(*self.frombin_map))[0])
		for y,rawrow in enumerate(array):
			row = []
			for x,cell_struct in enumerate(list(zip(*self.frombin_map))[1]):
				if type(cell_struct['func']) == FunctionType:
					cell = []
					cell.append('0')
					row.append(self.transformtostr(cell,**cell_struct))
				else:
					cell = []
					if (cell_struct['v'] == -1):
						i = cell_struct['sap']
						for j in range(cell_struct['l']):
							processed_data=list(struct.unpack_from('<'+str((cell_struct['s']//len(cell_struct['st']))*cell_struct['stp'])+"".join(cell_struct['st']),rawrow,i))[::cell_struct['stp']]
							#if (x == 4) and (y == 70):
							#	#print(cell_struct['s'])
							cell.append(processed_data)
							i=i+cell_struct['s']*struct.calcsize("".join(cell_struct['st']))*cell_struct['stp'] #sizeof here
						if (cell_struct['t'] == 'rcolor'):
							cell[0].reverse()
					else:
						cell.append(cell_struct['v'])
					#if y == 70:
					#	print(cell) #'s':0x02,'l':0x08
					row.append(self.transformtostr(cell,**cell_struct))
			self.list.append(row)

		for x,row in enumerate(self.list):
			if x>0:
				for func_index in struct_func_indexes:
					self.list[x][func_index] = list(zip(*self.frombin_map))[1][func_index]['func'](func_index, row)
				
				deletions = 0
				for z,struct_item_name in enumerate(list(zip(*self.frombin_map))[0]):
					if (struct_item_name == ''):
						del	self.list[x][z-deletions]
						deletions = deletions + 1
		return

	def i(self,x):
		for i,v in enumerate(self.list):
			if(x==v):
				return i
				break
		return -1

	def j(self,x):
		for i,v in enumerate(list(zip(*self.frombin_map))[0]):
			if(x==v):
				return i
				break
		return -1

	def remap(self,v):
		for i,n in enumerate(list(zip(*v))[0]):
			if self.j(n) == -1:
				self.frombin_map.append((list(zip(*v))[0][i],list(zip(*v))[1][i]))
			else:
				if (list(zip(*v))[1][i] == {}):
					del self.frombin_map[self.j(n)]
				else:
					self.frombin_map[self.j(n)] = (list(zip(*v))[0][i],list(zip(*v))[1][i])

	def bintotsv(self):
		file = open(self.file_name+'.txt', 'wt', encoding=self.encoding)
		for i,a in enumerate(self.list):
			a=list(a)
			if (i==0):
				deletions = 0
				for z,item in enumerate(a[:]):
					if (item == ''):
						del	a[z-deletions]
						deletions = deletions + 1
				file.write('//'+'\t'.join(a))
			else:
				#print(a)
				file.write('\n'+'\t'.join(a))
		file.close()
		return self

		def trim_nullbytestr(string, flag=0): #flag=1, return "0" when string is empty
			result = string
			for i,byte in enumerate(string[:]):
				if byte == '\00':
					result = string[:i]
					break
			if (flag & 1) and ((string == '\00') or (string == '')):
				result = '0'
			return result

	def transformtostr(self,result,t,s,l,stp,f,v,ea,eap,lpad,rpad,sa,sap,st,sm,lm,smb,smea,sv,func):
		if v != -1:
			return str(v)
		_type = t
		j = 0
		for n,v in enumerate(result[:]):
			m = 0
			if type(t) == tuple:
				_type = t[j]
			is_integer = not((_type=="float") or (_type=="double") or (_type=="str") or (_type=="char") or (_type=="_bool"))
			if is_integer:
				if f==-1:
					f=0
			for k,w in enumerate(v[:]):
				if is_integer:
					#Result: flag=0x0001 = remove FF's, #flag=0x0002 = cut file defect bytes, #flag=0x0004 = remove 0's, #flag=0x0008 = return space instead of nil, #flag=0x0010 = multiply number by 100, #flag=0x0020 = return -1 if empty
					if ((((f & 0x4) and (w == 0))) or
					((f & 0x1) and ((w == (2**8)-1) or (w == (2**16)-1) or (w == (2**32)-1) or (w == (2**64)-1) or (w == -1))) or
					((f & 0x2) and ((((_type=="byte") or (_type=="ubyte")) and (w == (2**8)-51)) or (((_type=="short") or (_type=="ushort")) and (w == (2**16)-12851)) or (((_type=="long") or (_type=="ulong")) and (w == (2**32)-842150451)) or (((_type=="quad") or (_type=="uquad")) and (w == (2**64)-3617008641903833651))))):
						del result[j][m]
						m=m-1
					else:
						if (f & 0x2 and w == 0):
							result[j] = result[j][:m]
							break
						if (f & 0x10):
							result[j][m]=result[j][m]*100
						result[j][m]=str(result[j][m])
					m=m+1

				if (_type=="float"):
					if f==-1:
						f=3
					result[j][k]=str(round(float(w),f))
				if (_type=="str"):
					#flag=0x1 = return "0" when string is empty, #flag=0x2 = strip space characters around string, #flag=0x8 = if first char = null, then make it space
					if f==-1:
						f=0
					if ((w[0] == 205) and (w[1] == 205)):
						result[j][m] = ''
					else:
						result[j][m] = w.decode(self.encoding,'ignore')
					if ((f & 0x8) and (w[0] == 0)):
						result[j][m] = ' '
					for o,x in enumerate(result[j][m]):
						if (x == '\00' or x == '\n'):
							result[j][m] = result[j][m][:o]
							break
					if (f & 0x2):
						result[j][m] = result[j][m].strip()
					if ((f & 0x1) and (result[j][m] == '')):
						result = '0'
			if (result[j] != '0'):
				result[j] = ','.join(result[j])
			if is_integer:
				if ((f & 0x20) and (result == '')):
					result = '-1'
				elif (result[j] == ''):
					result[j] = '0'
			j=j+1
		if (_type=="str"):
			result = ','.join(result)
			if ((f & 1) and (result == '')):
				result = '0'
		else:
			result = ';'.join(result)
		if is_integer:
			if ((f & 0x20) and (result == '')):
				result = '-1'
			elif (result == ''):
				result = '0'
		return result

#---------------------------------------------

#map(None,*list) = zip(*list)

class areaset(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'					,{'t':'ulong','lpad':0x04}),
			('Name'					,{'t':'str','s':0x48,'rpad':0x1C,'f':0x08}),
			('RGB color'			,{'t':'color','rpad':0x01}),
			('Sound effect ID'		,{'t':'long'}),
			('Color RGB'			,{'t':'rcolor','rpad':0x01}),
			('Lighting RGB value'	,{'t':'rcolor','rpad':0x01}),
			('Lighting angle'		,{'t':'float','s':0x03,'f':0x01}),
			('Is it city?'			,{'t':'ubyte','rpad':0x03})
		]

class characterinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'							,{'t':'long','lpad':0x04}),
			('Name'							,{'t':'str','s':0x48,'rpad':0x40}),
			('Short Name'					,{'t':'str','s':0x10,'rpad':0x01}),
			('Model Type'					,{'t':'ubyte'}),
			('Logic Type'					,{'t':'ubyte','rpad':0x01}),
			('Framework Number'				,{'t':'ushort'}),
			('Suite Serial'					,{'t':'ushort'}),
			('Suite Quantity'				,{'t':'ushort'}),
			('Part 00'						,{'t':'ushort'}),
			('Part 01'						,{'t':'ushort'}),
			('Part 02'						,{'t':'ushort'}),
			('Part 03'						,{'t':'ushort'}),
			('Part 04'						,{'t':'ushort'}),
			('Part 05'						,{'t':'ushort'}),
			('Part 06'						,{'t':'ushort'}),
			('Part 07'						,{'t':'ushort'}),
			('FeffID'						,{'t':'ushort','s':0x02}),
			('EeffID'						,{'t':'ushort','rpad':0x04}),
			('Special Effect Action Serial'	,{'t':'ushort','s':0x03}),
			('Shadow'						,{'t':'ushort'}),
			('Action ID'					,{'t':'ushort'}),
			('Transparency'					,{'t':'ubyte','rpad':0x01}),
			('Moving Sound Effect'			,{'t':'short'}),
			('Breathing Sound Effect'		,{'t':'short'}),
			('Death Sound Effect'			,{'t':'short'}),
			('Can it be controlled?'		,{'t':'ubyte'}),
			('Area Limited?'				,{'t':'ubyte'}),
			('Altitude Excursion'			,{'t':'short'}),
			('Item types that can equip'	,{'t':'short','s':0x06,'rpad':0x1E}),
			('Length'						,{'t':'float'}),
			('Width'						,{'t':'float'}),
			('Height'						,{'t':'float'}),
			('Collision Range'				,{'t':'ushort'}),
			('Birth'						,{'t':'ubyte','s':0x02,'rpad':0x01}),
			('Death'						,{'t':'ubyte','s':0x02,'rpad':0x01}),
			('Birth Effect'					,{'t':'ushort'}),
			('Death Effect'					,{'t':'ushort'}),
			('Hibernate Action'				,{'t':'ubyte','rpad':0x01}),
			('Death Instant Action'			,{'t':'ubyte','rpad':0x01}),
			('Remaining HP Effect Display'	,{'t':'ulong','s':0x03}),
			('Attack can swerve'			,{'t':'ubyte'}),
			('Confirm to blow away'			,{'t':'ubyte','rpad':0x02}),
			('Script'						,{'t':'ulong'}),
			('Weapon Used'					,{'t':'ulong'}),
			('Skill ID'						,{'t':'long','s':0x0B,'stp':0x2,'sm':1}),
			('Skill Rate'					,{'t':'long','s':0x0B,'stp':0x2,'lm':1,'lpad':0x4}),
			('Drop ID'						,{'t':'long','s':0x0A,'stp':0x2,'sm':1}),
			('Drop Rate'					,{'t':'long','s':0x0A,'stp':0x2,'lm':1,'lpad':0x4}),
			('Quantity Limit'				,{'t':'ulong','sm':1,'lpad':0x50}),
			('Fatality Rate'				,{'t':'ulong'}),
			('Prefix Lvl'					,{'t':'ulong'}),
			('Quest Drop ID'				,{'t':'long','s':0x0A,'stp':0x2,'lm':1,'smb':2}),
			('Quest Drop Rate'				,{'t':'long','s':0x0A,'stp':0x2,'lm':1,'lpad':0x4}),
			('AI'							,{'t':'ulong','lm':2}),
			('Turn?'						,{'t':'ubyte','rpad':0x03}),
			('Vision'						,{'t':'ulong'}),
			('Noise'						,{'t':'ulong'}),
			('GetExp'						,{'t':'ulong'}),
			('Light'						,{'t':'ubyte','rpad':0x03}),
			('MobExp'						,{'t':'ulong'}),
			('Level'						,{'t':'ulong'}),
			('Max HP'						,{'t':'long'}),
			('Current HP'					,{'t':'long'}),
			('Max SP'						,{'t':'long'}),
			('Current SP'					,{'t':'long'}),
			('Minimum Attack'				,{'t':'long'}),
			('Maximum Attack'				,{'t':'long'}),
			('Physical Resistance'			,{'t':'long'}),
			('Defense'						,{'t':'long'}),
			('Hit rate'						,{'t':'long'}),
			('Dodge rate'					,{'t':'long'}),
			('Critical Chance'				,{'t':'long'}),
			('Drop Rate Chance'				,{'t':'long'}),
			('HP Recovery Per Cycle'		,{'t':'long'}),
			('SP Recovery Per Cycle'		,{'t':'long'}),
			('Attack Speed'					,{'t':'long'}),
			('Attack Distance'				,{'t':'long'}),
			('Chase Distance'				,{'t':'long'}),
			('Movement Speed'				,{'t':'long'}),
			('Col'							,{'t':'long'}),
			('Strength'						,{'t':'long'}),
			('Agility'						,{'t':'long'}),
			('Accuracy'						,{'t':'long'}),
			('Constitution'					,{'t':'long'}),
			('Spirit'						,{'t':'long'}),
			('Luck'							,{'t':'long'}),
			('Left_Rad'						,{'t':'ulong'}),
			('Guild ID'						,{'t':'str','s':0x20,'rpad':0x01}),
			('Title'						,{'t':'str','s':0x20,'rpad':0x01}),
			('Class'						,{'t':'str','s':0x10,'rpad':0x02}),
			('Experience'					,{'t':'ulong'}),
			('Next Level Experience'		,{'t':'ulong','lpad':0x04}),
			('Reputation'					,{'t':'ulong'}),
			('AP'							,{'t':'ushort'}), #dunno rly
			('TP'							,{'t':'ushort'}), #dunno rly
			('GD'							,{'t':'ulong'}),
			('SPRI'							,{'t':'ulong'}),
			('Story'						,{'t':'ulong'}),
			('Max Sail'						,{'t':'ulong'}),
			('Sail'							,{'t':'ulong'}),
			('StaSA'						,{'t':'ulong'}),
			('SCSM'							,{'t':'ulong'}),
			('TStrength'					,{'t':'long'}),
			('TAgility'						,{'t':'long'}),
			('TAccuracy'					,{'t':'long'}),
			('TConstitution'				,{'t':'long'}),
			('TSpirit'						,{'t':'long'}),
			('TLuck'						,{'t':'long'}),
			('TMax HP'						,{'t':'long'}),
			('TMax SP'						,{'t':'long'}),
			('TAttack'						,{'t':'long'}),
			('TDefense'						,{'t':'long'}),
			('THit Rate'					,{'t':'long'}),
			('TDodge Rate'					,{'t':'long'}),
			('TDrop Rate Chance'			,{'t':'long'}),
			('TCritical Rate Chance'		,{'t':'long'}),
			('THP Recovery'					,{'t':'long'}),
			('TSP Recovery'					,{'t':'long'}),
			('TAttack Speed'				,{'t':'long'}),
			('TAttack Distance'				,{'t':'long'}),
			('TMovement Speed'				,{'t':'long'}),
			('TSPRI'						,{'t':'ulong'}),
			('TSCSM'						,{'t':'ulong'}),
			('chasf'						,{'t':'float','s':0x03,'rpad':0x4})
		]
		if self.version == 1:
			self.remap([
				('Name'							,{'t':'str','s':0x48,'rpad':0x31}),
				('Logic Type'					,{'t':'ubyte'}),
				('TSCSM'						,{'t':'ulong','rpad':0x4}),
				('chasf'						,{})
			])
		if self.version >= 3:
			self.remap([
				('Name'							,{'t':'str','s':0x48,'rpad':0x48}),
				('Short Name'					,{'t':'str','s':0x20,'rpad':0x08}),
				('Logic Type'					,{'t':'ubyte'}),
				('Item types that can equip'	,{'t':'short','s':0x06,'rpad':0x1C}),
				('TSCSM'						,{'t':'ulong','rpad':0x08}),
				('chasf'						,{'t':'float','s':0x03,'rpad':0xC})
			])
		if self.version == 5:
			self.remap([
				('Name'							,{'t':'str','s':0x48,'rpad':0x48}),
				('Short Name'					,{'t':'str','s':0x20,'rpad':0x08}),
				('Logic Type'					,{'t':'ubyte'}),
				('Item types that can equip'	,{'t':'short','s':0x06,'rpad':0x1C}),
				('TSCSM'						,{'t':'ulong','rpad':0x08}),
				('chasf'						,{'t':'float','s':0x03,'rpad':0x4})
			])

class characterposeinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('Pose'			,{'t':'str','s':0x48,'rpad':0x1C}),
			('Fists'		,{'t':'ushort'}),
			('Sword'		,{'t':'ushort'}),
			('2H Sword'		,{'t':'ushort'}),
			('Dual Swords'	,{'t':'ushort'}),
			('Firegun'		,{'t':'ushort'}),
			('Bow'			,{'t':'ushort'}),
			('Dagger'		,{'t':'ushort','rpad':0x02})
		]

class chaticons(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('File'		,{'t':'str','s':0x48,'rpad':0x2C}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'ulong'}),
			('File2'	,{'t':'str','s':0x10}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'ulong'}),
			('File3'	,{'t':'str','s':0x10}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'ulong','rpad':0x1C}),
			('?'		,{'t':'ulong'})
		]

class elfskillinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('Name'		,{'t':'str','s':0x48,'rpad':0x1C}),
			('Kind ID'	,{'t':'ulong','sm':1,'lpad':0x04}),
			('Level'	,{'t':'ulong','lm':1})
		]

class eventsound(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('Name'		,{'t':'str','s':0x48,'rpad':0x1C}),
			('Sound ID'	,{'t':'ulong'})
		]

class forgeitem(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('Level'			,{'t':'ubyte','sm':1,'lpad':0x6C}),
			('Failed Level'		,{'t':'str','s':0x48,'lm':1,'smb':2,'lpad':0x08}),
			('Success Rate'		,{'t':'ubyte','lm':2,'lpad':0x01,'rpad':0x05}),
			('Requirement 1'	,{'t':('ushort','ubyte'),'rpad':0x01}),
			('Requirement 2'	,{'t':('ushort','ubyte'),'rpad':0x01}),
			('Requirement 3'	,{'t':('ushort','ubyte'),'rpad':0x01}),
			('Requirement 4'	,{'t':('ushort','ubyte'),'rpad':0x01}),
			('Requirement 5'	,{'t':('ushort','ubyte'),'rpad':0x01}),
			('Requirement 6'	,{'t':('ushort','ubyte'),'rpad':0x01}),
			('Required Gold'	,{'t':'ulong','lm':2,'lpad':0x03})
		]

class hairs(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'				,{'t':'ulong','lpad':0x04}),
			('Name'				,{'t':'str','s':0x48,'rpad':0x1C}),
			('Color'			,{'t':'str','s':0x08,'rpad':0x04}),
			('Required Item 0'	,{'t':'ulong','s':0x02}),
			('Required Item 1'	,{'t':'ulong','s':0x02}),
			('Required Item 2'	,{'t':'ulong','s':0x02}),
			('Required Item 3'	,{'t':'ulong','s':0x02}),
			('Required Gold'	,{'t':'ulong'}),
			('Model'			,{'t':'ulong'}),
			('Failed Model'		,{'t':'ulong','rpad':0x08}),
			('For Lance?'		,{'t':'ubyte'}),
			('For Carsise?'		,{'t':'ubyte'}),
			('For Phyllis?'		,{'t':'ubyte'}),
			('For Ami?'			,{'t':'ubyte','rpad':0x04})
		]
		if self.version >= 3:
			self.remap([
				('Color'			,{'t':'str','s':0x20,'rpad':0x08})
			])

class iteminfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'									,{'t':'ulong','lpad':0x04}),
			('Name'									,{'t':'str','s':0x4C,'rpad':0x6C}),
			('Icon Name'							,{'t':'str','s':0x10,'rpad':0x01}),
			('Model (Ground)'						,{'t':'str','s':0x10,'rpad':0x03}),
			('Model (Lance)'						,{'t':'str','s':0x10,'rpad':0x03}),
			('Model (Carsise)'						,{'t':'str','s':0x10,'rpad':0x03}),
			('Model (Phyllis)'						,{'t':'str','s':0x10,'rpad':0x03}),
			('Model (Ami)'							,{'t':'str','s':0x10,'rpad':0x03}),
			('Ship Symbol'							,{'t':'ushort'}),
			('Ship Size'							,{'t':'ushort'}),
			('Item Type'							,{'t':'ushort'}),
			('Obtain Prefix Rate'					,{'v':0}),
			('Set ID'								,{'v':0}),
			('Forging Level'						,{'t':'ubyte'}),
			('Stable Level'							,{'t':'ubyte'}),
			('Repairable'							,{'t':'ubyte'}),
			('Tradable'								,{'t':'ubyte'}),
			('Pick-upable'							,{'t':'ubyte'}),
			('Droppable'							,{'t':'ubyte'}),
			('Deletable'							,{'t':'ubyte','smea':1,'rpad':0x23}),
			('Max Stack Size'						,{'t':'ulong'}),
			('Instance'								,{'t':'ubyte'}),
			('Price'								,{'t':'ulong','lm':1,'smb':2,'lpad':0x03}),
			('Character Types'						,{'t':'byte','s':4}),
			('Character Level'						,{'t':'ushort'}),
			('Character Classes'					,{'t':'byte','s':0x13,'rpad':0x03}),
			('Character Nick'						,{'v':0}),
			('Character Reputation'					,{'v':0}),
			('Equipable Slots'						,{'t':'byte','s':0x0A,'lm':2}),
			('Item Switch Locations'				,{'t':'byte','s':0x0A}),
			('Item Obtain Into Location Determine'	,{'t':'ubyte'}),
			('+STR %'								,{'t':'short'}),
			('+AGI %'								,{'t':'short'}),
			('+ACC %'								,{'t':'short'}),
			('+CON %'								,{'t':'short'}),
			('+SPR %'								,{'t':'short'}),
			('+LUK %'								,{'t':'short'}),
			('+Attack Speed %'						,{'t':'short'}),
			('+Attack Range %'						,{'t':'short'}),
			('+Min Attack %'						,{'t':'short'}),
			('+Max Attack %'						,{'t':'short'}),
			('+Defense %'							,{'t':'short'}),
			('+Max HP %'							,{'t':'short'}),
			('+Max SP %'							,{'t':'short'}),
			('+Dodge Rate %'						,{'t':'short'}),
			('+Hit Rate %'							,{'t':'short'}),
			('+Critical Rate %'						,{'t':'short'}),
			('+Treasure Drop Rate %'				,{'t':'short'}),
			('+HP Recovery %'						,{'t':'short'}),
			('+SP Recovery %'						,{'t':'short'}),
			('+Movement Speed %'					,{'t':'short'}),
			('+Resource Gathering Rate %'			,{'t':'short'}),
			('+STR (Min,Max)'						,{'t':'short','s':0x02}),
			('+AGI'									,{'t':'short','s':0x02}),
			('+ACC'									,{'t':'short','s':0x02}),
			('+CON'									,{'t':'short','s':0x02}),
			('+SPR'									,{'t':'short','s':0x02}),
			('+LUK'									,{'t':'short','s':0x02}),
			('+Attack Speed'						,{'t':'short','s':0x02}),
			('+Attack Range'						,{'t':'short','s':0x02}),
			('+Min Attack'							,{'t':'short','s':0x02}),
			('+Max Attack'							,{'t':'short','s':0x02}),
			('+Defense'								,{'t':'short','s':0x02}),
			('+Max HP'								,{'t':'short','s':0x02}),
			('+Max SP'								,{'t':'short','s':0x02}),
			('+Dodge'								,{'t':'short','s':0x02}),
			('+Hit Rate'							,{'t':'short','s':0x02}),
			('+Critical Rate'						,{'t':'short','s':0x02}),
			('+Treasure Drop Rate'					,{'t':'short','s':0x02}),
			('+HP Recovery'							,{'t':'short','s':0x02}),
			('+SP Recovery'							,{'t':'short','s':0x02}),
			('+Movement Speed'						,{'t':'short','s':0x02}),
			('+Resource Gathering Rate'				,{'t':'short','s':0x02}),
			('+Physical Resist'						,{'t':'short','s':0x02}),
			('Aftected By Left Hand Efs'			,{'t':'short'}),
			('+Energy'								,{'t':'ushort','s':0x02,'sm':1,'lpad':0x04,'smea':2}),
			('+Durability'							,{'t':'ushort','s':0x02,'lm':1}),
			('Gem Sockets'							,{'t':'ushort','lm':2}),
			('Ship Durability Recovery'				,{'v':0}),
			('Ship Cannon Amount'					,{'v':0}),
			('Ship Member Count'					,{'v':0}),
			('Ship Label'							,{'v':0}),
			('Ship Cargo Capacity'					,{'v':0}),
			('Ship Fuel Consumption'				,{'v':0}),
			('Ship Attack Speed'					,{'v':0}),
			('Ship Movement Speed'					,{'v':0}),
			('Usage Script'							,{'t':'str','s':0x20,'rpad':0x02}),
			('Display Effect'						,{'t':'ushort'}),
			('Bind Effect'							,{'t':'ushort','s':0x08,'stp':0x2,'sm':1}),
			('Bind Effect 2'						,{'t':'ushort','s':0x08,'stp':0x2,'lm':1,'lpad':0x2}),
			('1st Inv Slot Effect'					,{'t':'ushort','s':0x02}),
			('Drop Model Effect'					,{'t':'ushort','s':0x02}),
			('Item Usage Effect'					,{'t':'ushort','s':0x02}),
			('Description'							,{'t':'str','s':0x100,'rpad':0x0C,'f':0x01})
		]
		if self.version == 1:
			self.remap([
				('Description'							,{'t':'str','s':0x80,'rpad':0x0C,'f':0x01})
			])
		if self.version >= 4:
			self.remap([
				('Equipable Slots'						,{'t':'byte','s':0x0E,'lm':2}),
				('Item Switch Locations'				,{'t':'byte','s':0x0E}),
			])
		if self.version == 7:
			self.remap([
				('Item Type'							,{'t':'ushort', 'rpad':0x02}),
				('Deletable'							,{'t':'ubyte','smea':1,'rpad':0x21}),
				('Price'								,{'t':'ulong','lm':1,'smb':2,'lpad':0x01}),
			])

class itempre(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('Name'		,{'t':'str','s':0x48,'rpad':0x1C})
		]

class itemrefineeffectinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'				,{'t':'ulong','lpad':0x04}),
			('Name'				,{'t':'str','s':0x48,'rpad':0x1C}),
			('?'				,{'t':'ulong'}),
			('ID 1 (Lance)'		,{'t':'ushort','smea':1,'rpad':0x06}),
			('ID 1 (Carsise)'	,{'t':'ushort','smea':2,'rpad':0x06}),
			('ID 1 (Phyllis)'	,{'t':'ushort','smea':3,'rpad':0x06}),
			('ID 1 (Ami)'		,{'t':'ushort','smea':4,'rpad':0x06}),
			('? 1'				,{'t':'ubyte','smea':5}),
			('ID 2 (Lance)'		,{'t':'ushort','lm':1,'smea':1}),
			('ID 2 (Carsise)'	,{'t':'ushort','lm':2,'smea':2}),
			('ID 2 (Phyllis)'	,{'t':'ushort','lm':3,'smea':3}),
			('ID 2 (Ami)'		,{'t':'ushort','lm':4,'smea':4}),
			('? 2'				,{'t':'ubyte','lm':5,'smea':5}),
			('ID 3 (Lance)'		,{'t':'ushort','lm':1,'smea':1}),
			('ID 3 (Carsise)'	,{'t':'ushort','lm':2,'smea':2}),
			('ID 3 (Phyllis)'	,{'t':'ushort','lm':3,'smea':3}),
			('ID 3 (Ami)'		,{'t':'ushort','lm':4,'smea':4}),
			('? 3'				,{'t':'ubyte','lm':5,'smea':5}),
			('ID 4 (Lance)'		,{'t':'ushort','lm':1}),
			('ID 4 (Carsise)'	,{'t':'ushort','lm':2}),
			('ID 4 (Phyllis)'	,{'t':'ushort','lm':3}),
			('ID 4 (Ami)'		,{'t':'ushort','lm':4}),
			('? 4'				,{'t':'ubyte','lm':5,'rpad':0x10})
		]

class itemrefineinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('Name'		,{'t':'str','s':0x48,'rpad':0x1C}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'ushort'}),
			('?'		,{'t':'float'}),
			('?'		,{'t':'float'}),
			('?'		,{'t':'float'}),
			('?'		,{'t':'float'})
		]

class itemtype(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('Name'		,{'t':'str','s':0x48,'rpad':0x1C})
		]

class magicgroupinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'				,{'t':'ulong','lpad':0x04,'rpad':0x64}),
			('Name'				,{'t':'str','s':0x20}),
			('Number of Types'	,{'t':'ulong'}),
			('Types'			,{'t':'long','s':0x08,'f':0x01}),
			('Quantities'		,{'t':'long','s':0x08,'rpad':0x04}),
			('?'				,{'t':'ulong'})
		]

class magicsingleinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('Name'		,{'t':'str','s':0x48,'rpad':0x3C}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'str','s':0x18,'l':0x08}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'str','s':0x18,'l':0x08}),
			('?'		,{'t':'long','s':0x08}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'ulong'}),
			('?'		,{'t':'str','s':0x18})
		]

class mapinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('File'		,{'t':'str','s':0x48,'rpad':0x1C}),
			('Name'		,{'t':'str','s':0x10,'smea':1,'rpad':0x17}),
			('?'		,{'t':'ubyte'}),
			('Coords'	,{'t':'ulong','s':0x02,'lm':1,'rpad':0x0C}),
			('?'		,{'v':''}),
			('Color'	,{'t':'color'})
		]
		if self.version == 6:
			self.remap([
				('Name'		,{'t':'str','s':0x20,'smea':1,'rpad':0x17})
			])

class musicinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('File'		,{'t':'str','s':0x48,'rpad':0x1C}),
			('?'		,{'t':'ulong'})
		]

class notifyset(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('?'			,{'t':'str','s':0x48,'rpad':0x1C}),
			('Hint Mode'	,{'t':'ubyte'}),
			('Message'		,{'t':'str','s':0x40,'rpad':0x03})
		]

class objevent(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('?'			,{'t':'str','s':0x48,'rpad':0x32}),
			('?'			,{'t':'ushort'}),
			('?'			,{'t':'ushort'}),
			('?'			,{'t':'ushort'}),
			('?'			,{'t':'ushort'}),
			('?'			,{'t':'ushort'}),
			('?'			,{'t':'ushort'}),
			('?'			,{'t':'ushort'}),
			('?'			,{'t':'ubyte','rpad':0x03})
		]

class resourceinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('File'			,{'t':'str','s':0x48,'rpad':0x1C}),
			('?'			,{'t':'ulong'})
		]

class sceneffectinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('File'			,{'t':'str','s':0x48,'rpad':0x1C}),
			('Name'			,{'t':'str','s':0x10}),
			('Image Name'	,{'t':'str','s':0x10,'rpad':0x04}),
			('Flag'			,{'t':'ulong'}),
			('ObjTypeID'	,{'t':'ulong','rpad':0x04}),
			('Dummy'		,{'t':'long','s':0x08,'f':0x21}),
			('Dummy 2'		,{'t':'long'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'float'}),
			('?'			,{'t':'float'}),
			('?'			,{'t':'float'})
		]

def specialdata(cindex,array):
	if (array[3] == '0'):
		return array[17]
	if (array[3] == '3'):
		return array[6]
	if (array[3] == '6'):
		return array[14]
	return '0'

def specialdata2(cindex,array):
    if (array[3] == '3'):
       return array[7]
    if (array[3] == '6'):
       return array[15]
    return '0'

class sceneobjinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('File'			,{'t':'str','s':0x48,'rpad':0x1C}),
			('Name'			,{'t':'str','s':0x10}),
			('?'			,{'t':'ulong'}),
			('?'			,{'v':0,'func':specialdata}),
			('?'			,{'v':0,'func':specialdata2}),
			(''			,{'t':'ubyte','s':0x03,'rpad':0x09}),
			(''			,{'t':('ulong','float','ulong')}),
			('?'			,{'t':'ulong','sm':1,'lpad':0x04}),
			('?'			,{'t':'ulong','smea':2,'lpad':0x04}),
			('?'			,{'t':'ulong','sm':3,'lm':2}),
			('?'			,{'t':'ulong','lm':1}),
			('?'			,{'t':'ulong','lm':3}),
			('?'			,{'t':'ulong'}),
			(''			,{'t':'str','s':0x0C}),
			(''			,{'t':'ulong','rpad':0x04}),
			('?'			,{'t':'ulong','rpad':0x04}),
			(''			,{'t':'ulong','s':0x0C,'rpad':0x18,'f':0x02}), #some defect with files makes this flag necessary
		]

class selectcha(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('Name'			,{'t':'str','s':0x48,'rpad':0x20}),
			('?'			,{'t':'ulong','smea':1,'rpad':0x100}),
			('?'			,{'t':'ulong','s':0x1,'smea':2}),
			('?'			,{'t':'ulong','s':0x38,'lm':1}),
			('?'			,{'t':'ulong','s':0x1,'lpad':0xFC,'lm':2,'rpad':0xFC}),
			('?'			,{'t':'ulong','s':0x1,'rpad':0xFC}),
			('?'			,{'t':'ulong','s':0x1,'rpad':0x0514})
		]


class serverset(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('Name'			,{'t':'str','s':0x48,'rpad':0x1C}),
			('Region'		,{'t':'str','s':0x10,'sm':1,'lpad':0x50,'rpad':0x04,'f':0x01}),
			('IP #1'		,{'t':'str','s':0x10,'lm':1,'f':0x01}),
			('IP #2'		,{'t':'str','s':0x10,'f':0x01}),
			('IP #3'		,{'t':'str','s':0x10,'f':0x01}),
			('IP #4'		,{'t':'str','s':0x10,'f':0x01}),
			('IP #5'		,{'t':'str','s':0x10,'f':0x01})
		]
		if self.version >= 3:
			self.remap([
				('Region'		,{'t':'str','s':0x10,'sm':1,'lpad':0x50,'smea':2,'f':0x01}),
				('Description'	,{'t':'str','s':0x0100,'lm':2,'lpad':0x01,'rpad':0x04}),
				('?'			,{'t':'str','s':0x10,'rpad':0x03})
			])

class shadeinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'			,{'t':'ulong','lpad':0x04}),
			('?'			,{'t':'str','s':0x48,'rpad':0x1C}),
			('?'			,{'t':'str','s':0x10,'rpad':0x04}),
			('?'			,{'t':'float'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'}),
			('?'			,{'t':'ulong'})
		]

def ship15id(cindex,array):
	return str(int(array[0])+1)

class shipinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'						,{'t':'ulong','lpad':0x04}),
			('Name'						,{'t':'str','s':0x48,'rpad':0x5C}),
			('Item ID'					,{'t':'ushort','sm':1,'lpad':0x80}),
			('Char ID'					,{'t':'ushort'}),
			('Action ID'				,{'t':'ushort','rpad':0x0A}),
			('Hull'						,{'t':'ushort','sm':2,'lpad':0x80,'smea':3}),
			('Engine'					,{'t':'short','s':0x10,'lm':2,'lpad':0x20,'f':0x04}),
			('Mobility'					,{'t':'short','s':0x10,'lm':2,'f':0x04}),
			('Cannon'					,{'t':'short','s':0x10,'lpad':0x20,'f':0x04}),
			('Component'				,{'t':'short','s':0x0C,'f':0x04}),
			('Level Restriction'		,{'t':'ushort','lm':3,'rpad':0x02}),
			('Class Restriction'		,{'t':'short','rpad':0x1E}),
			('Durability'				,{'t':'ushort'}),
			('Durability Recovery'		,{'t':'ushort'}),
			('Defense'					,{'t':'ushort'}),
			('Physical Resist'			,{'t':'ushort'}),
			('Min Attack'				,{'t':'ushort'}),
			('Max Attack'				,{'t':'ushort'}),
			('Attack Range'				,{'t':'ushort'}),
			('Reloading Time'			,{'t':'ushort'}),
			('Cannon Area of Effect'	,{'t':'ushort'}),
			('Cargo Capacity'			,{'t':'ushort'}),
			('Fuel'						,{'t':'ushort'}),
			('Fuel Consumption'			,{'t':'ushort'}),
			('Attack Speed'				,{'t':'ushort'}),
			('Movement Speed'			,{'t':'ushort','smea':2}),
			('Description'				,{'t':'str','s':0x80,'lm':1}),
			('Remark'					,{'t':'ushort','lm':2})
		]
		if self.version == 1:
			self.frombin_map[0:0] = [
				(''							,{'t':'ulong','lpad':0x04})
			]
			self.remap([
				('ID'						,{'v':0,'func':ship15id})
			])
		if self.version >= 3:
			self.remap([
				('Hull'						,{'t':'ushort','sm':2,'lpad':0x98,'smea':3}),
				('Engine'					,{'t':'short','s':0x13,'lm':2,'lpad':0x26,'f':0x04}),
				('Mobility'					,{'t':'short','s':0x13,'lm':2,'smea':4,'f':0x04}),
				('Cannon'					,{'t':'short','s':0x13,'lpad':0x26,'f':0x04}),
				('Component'				,{'t':'short','s':0x0F,'f':0x04}),
				('Class Restriction'		,{'t':'short','rpad':0x24}),
				('Remark'					,{'t':'ushort','lm':2,'rpad':0x02})
			])

class shipiteminfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'						,{'t':'ulong','lpad':0x04}),
			('Name'						,{'t':'str','s':0x48,'rpad':0x5C}),
			('Model'					,{'t':'ulong','sm':1,'lpad':0x80}),
			('Propeller 1'				,{'t':'ushort'}),
			('Propeller 2'				,{'t':'ushort'}),
			('Propeller 3'				,{'t':'ushort'}),
			('Propeller 4'				,{'t':'ushort'}),
			('Price'					,{'t':'ulong'}),
			('Durability'				,{'t':'ushort'}),
			('Durability Recovery'		,{'t':'ushort'}),
			('Defense'					,{'t':'ushort'}),
			('Physical Resist'			,{'t':'ushort'}),
			('Min Attack'				,{'t':'ushort'}),
			('Max Attack'				,{'t':'ushort'}),
			('Attack Range'				,{'t':'ushort'}),
			('Reloading Time'			,{'t':'ushort'}),
			('Cannon Area of Effect'	,{'t':'ushort'}),
			('Cargo Capacity'			,{'t':'ushort'}),
			('Fuel'						,{'t':'ushort'}),
			('Fuel Consumption'			,{'t':'ushort'}),
			('Attack Speed'				,{'t':'ushort'}),
			('Movement Speed'			,{'t':'ushort','smea':2}),
			('Description'				,{'t':'str','s':0x80,'lm':1}),
			('Remark'					,{'t':'ushort','lm':2,'rpad':0x02})
		]
		if self.version == 1:
			self.frombin_map[0:0] = [
				(''							,{'t':'ulong','lpad':0x04})
			]
			self.remap([
				('ID'						,{'v':0,'func':ship15id})
			])

class skilleff(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'									,{'t':'ulong','lpad':0x04}),
			('Name'									,{'t':'str','s':0x48,'rpad':0x2E}), #to 0x30
			('Activation Interval'					,{'t':'short'}),
			('Transfer Persists Duration'			,{'t':'str','s':0x20,'f':0x01}),
			('Use Effect Script'					,{'t':'str','s':0x20,'f':0x01}),
			('Remove Effect Script'					,{'t':'str','s':0x20,'f':0x01}),
			('Can it be Manually Cancelled?'		,{'t':'ubyte'}),
			('Can Move?'							,{'t':'ubyte'}),
			('Can use Skill?'						,{'t':'ubyte'}),
			('Can use Normal Attack?'				,{'t':'ubyte'}),
			('Can Trade?'							,{'t':'ubyte'}),
			('Can use Items?'						,{'t':'ubyte'}),
			('Can Attack?'							,{'t':'ubyte'}),
			('Can be Attacked?'						,{'t':'ubyte'}),
			('Can be Item Target?'					,{'t':'ubyte'}),
			('Can be Skill Target?'					,{'t':'ubyte'}),
			('Can be Invisible?'					,{'t':'ubyte'}),
			('Can be Seen as Yourself?'				,{'t':'ubyte'}),
			('Can use Inventory?'					,{'t':'ubyte'}),
			('Can Talk to NPC?'						,{'t':'ubyte'}),
			('Remove Effect ID'						,{'t':'ubyte'}),
			('Screen Effect'						,{'t':'ubyte'}),
			('Client Performance'					,{'t':'ubyte','rpad':0x03}),
			('Client Display ID'					,{'t':'short'}),
			('Ground Status Effect'					,{'t':'short'}),
			('Center Display'						,{'t':'ubyte'}),
			('Knock out Display'					,{'t':'ubyte'}),
			('Special Effect of Recipe'				,{'t':'ushort'}),
			('Dummy 1'								,{'t':'short'}),
			('Display Effect When Attacked With?'	,{'t':'ubyte'}),
			('Dummy 2'								,{'t':'ubyte','rpad':0x08}) #changed to 0x10
		]
		if ((self.version == 6) or (self.version == 7)):
			self.remap([
				('Name'		,{'t':'str','s':0x48,'rpad':0x30,'f':0x01}),
				('Dummy 2'	,{'t':'ubyte','rpad':0x0A})
			])
		if (self.version >= 8):
			self.remap([
				('Name'		,{'t':'str','s':0x48,'rpad':0x2E,'f':0x01}),
				('Dummy 2'	,{'t':'ubyte','rpad':0x0C})
			])

class skillinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'									,{'t':'ulong','lpad':0x04}),
			('Name'									,{'t':'str','s':0x48,'rpad':0x2F}),
			('Not Life Skill?'						,{'t':'byte'}),
			('Class Requirement'					,{'t':'byte','s':0x02,'l':0x04,'rpad':0x0A}),
			('Left Hand Requirement'				,{'t':'short','s':0x02,'l':0x08}),
			('Right Hand Requirement'				,{'t':'short','s':0x02,'l':0x08}),
			('Armor Requirement'					,{'t':'short','s':0x02,'l':0x08}),
			('Conch Usage'							,{'t':'short','s':0x03,'rpad':0x2A}),
			('Skill Phase'							,{'t':'byte'}),
			('Skill Type'							,{'t':'byte','smea':1,'rpad':0x16}),
			('Useful/Harmful'						,{'t':'byte','smea':2}),
			('Learning Level'						,{'t':'short','lm':1}),
			('Prerequisite'							,{'t':'short','s':0x02,'l':0x03}),
			('Skill Points Consumption'				,{'t':'byte'}),
			('Discharged Status'					,{'t':'byte'}),
			('Apply Point'							,{'t':'byte','rpad':0x01}),
			('Cast Range'							,{'t':'ushort'}),
			('Process Target'						,{'t':'byte'}),
			('Attack Mode'							,{'t':'byte'}),
			('Angle'								,{'t':'short','lm':2,'lpad':0x01}),
			('Radius'								,{'t':'short'}),
			('Region Shape'							,{'t':'byte'}),
			('Prophase Management Formula'			,{'t':'str','s':0x20,'rpad':0x85,'smea':1}), #prev: 0x01
			('Add Surface Formula'					,{'t':'str','s':0x20,'rpad':0x01,'smea':2}),
			('SP Formula'							,{'t':'str','s':0x20,'lpad':0x01,'rpad':0x01,'lm':1}), #5
			('Durability Consumption Formula'		,{'t':'str','s':0x20,'rpad':0x01}),
			('Top-up Consumption Formula'			,{'t':'str','s':0x20,'rpad':0x01}), #appears as #2
			('Region Formula'						,{'t':'str','s':0x20,'rpad':0x01}),
			('Discharge Phase Formula'				,{'t':'str','s':0x20,'lpad':0x01,'rpad':0x01,'lm':2}),
			('Effect Phase Formula'					,{'t':'str','s':0x20,'rpad':0x01}),
			('Positive Effect Formula'				,{'t':'str','s':0x20,'rpad':0x01}),
			('Opposing Effect Formula'				,{'t':'str','s':0x20,'rpad':0x02}),
			('Bind Status ID Can Removed Manually'	,{'t':'ulong','rpad':0x16}),
			('Self Parameter'						,{'v':0}),
			('Self Effect'							,{'v':0}),
			('Consumable'							,{'v':0}),
			('Duration'								,{'v':0}),
			('Target Parameter'						,{'v':0}),
			('Splash Parameter'						,{'t':'short'}),
			('Duration on Target'					,{'t':'short'}),
			('Splash Persists Effect'				,{'t':'short'}),
			('Morph ID'								,{'t':'short'}),
			('Summon ID'							,{'t':'short','rpad':0x02}),
			('Discharge Duration'					,{'v':0}),
			('Repeated Discharge Duration'			,{'t':'str','s':0x20,'rpad':0x01}),
			('Damage Effect'						,{'t':'short','sm':3,'lpad':0x03}),
			('Play Effect'							,{'t':'byte','rpad':0x01}),
			('Action'								,{'t':'short','s':0x0A}),
			('Keyframe'								,{'t':'short'}),
			('Attack Sound Effect'					,{'t':'short'}),
			('Character Dummy'						,{'t':'short','s':0x02,'rpad':0x02}),
			('Character Effect'						,{'t':'ushort','s':0x02,'rpad':0x02}),
			('Base Standard Value'					,{'t':'ushort','s':0x02,'rpad':0x02}),
			('Item Dummy'							,{'t':'short'}),
			('Item Effect'							,{'t':'short','s':0x02}),
			('Item Effect 2'						,{'t':'short','s':0x02}),
			('Path of Flight Keyframe'				,{'t':'short'}),
			('Character Dummy'						,{'t':'short'}),
			('Item Dummy 2'							,{'t':'short'}),
			('Path of Flight Effect'				,{'t':'short'}),
			('Path of Flight Speed'					,{'t':'short'}),
			('Attacked Sound Effect'				,{'t':'short'}),
			('Dummy'								,{'t':'short'}),
			('Character Attacked Effect'			,{'t':'short'}),
			('Effect Duration Point'				,{'t':'byte','rpad':0x01}),
			('Surface Attacked Effect'				,{'t':'short'}),
			('Water Surface Effect'					,{'t':'short'}),
			('Icon'									,{'t':'str','s':0x10,'rpad':0x01}),
			('Play Count'							,{'t':'byte','smea':4}),
			('Command'								,{'t':'byte','s':0x02,'lm':3}),
			('Description'							,{'t':'str','s':0x80,'lm':4}),
			('Effect'								,{'t':'str','s':0x80}),
			('Consumption'							,{'t':'str','s':0x80,'rpad':0x2E})
		]
		if self.version == 6:
			self.remap([
				('Consumption'	,{'t':'str','s':0x80,'rpad':0x32})
			])

class stoneinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'		,{'t':'ulong','lpad':0x04}),
			('File'		,{'t':'str','s':0x48,'rpad':0x1C}),
			('Item ID'	,{'t':'ulong'}),
			('?'		,{'t':'ulong','s':0x03}),
			('?'		,{'t':'ulong'}),
			('Script'	,{'t':'str','s':0x40})
		]

class terraininfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		self.frombin_map = [
			('ID'	,{'t':'ulong','lpad':0x04}),
			('File'	,{'t':'str','s':0x48,'rpad':0x1C}),
			('?'	,{'t':'ulong','rpad':0x04}),
			('?'	,{'t':'ulong'})
		]

class helpinfoset(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		if self.version >= 3:
			self.frombin_map = [
				('ID'			,{'t':'ulong','lpad':0x04}),
				('Name'			,{'t':'str','s':0x48,'rpad':0x1C}),
				('Description'	,{'t':'str','s':0x800})
			]

class monsterlist(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		if self.version >= 3:
			self.frombin_map = [
				('ID'			,{'t':'ulong','lpad':0x04,'rpad':0x64}),
				('Name'			,{'t':'str','s':0x80}),
				('Level'		,{'t':'str','s':0x80}),
				('Coordinates'	,{'t':'ulong','s':0x02}),
				('Map'			,{'t':'str','s':0x80})
			]

class npclist(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		monsterlist.__init__(self, file_name, version, encoding)

class monsterinfo(top_tsv):
	def __init__(self, file_name=0, version=0, encoding=0):
		top_tsv.__init__(self, file_name, version, encoding)
		if self.version >= 4:
			self.frombin_map = [
				('ID'					,{'t':'ulong','lpad':0x04}),
				('Name'					,{'t':'str','s':0x48,'rpad':0x3C}),
				('Start Coordinates'	,{'t':'ulong','s':0x02,'f':0x10}),
				('End Coordinates'		,{'t':'ulong','s':0x02,'f':0x10}),
				('Char IDs'				,{'t':'ulong','s':0x02,'rpad':0x18}),
				('Map'					,{'t':'str','s':0x10,'rpad':0x10})
			]

toptablebins = [
      areaset,
      characterinfo,
      characterposeinfo,
      chaticons,
      elfskillinfo,
      eventsound,
      forgeitem,
      hairs,
      iteminfo,
      itempre,
      itemrefineeffectinfo,
      itemrefineinfo,
      itemtype,
      magicgroupinfo,
      magicsingleinfo,
      mapinfo,
      monsterinfo,
      musicinfo,
      notifyset,
      objevent,
      resourceinfo,
      sceneffectinfo,
      sceneobjinfo,
      serverset,
      selectcha,
      shadeinfo,
      shipinfo,
      shipiteminfo,
      skilleff,
      skillinfo,
      stoneinfo,
      terraininfo,
      helpinfoset,
      monsterlist,
      npclist
]

def decompile_bin_folder(folder, version, encoding='gbk'):
	print('Folder to decompile: '+folder)
	for c in toptablebins:
		myc = c(folder+c.__name__, version, encoding)
		try:
			myc.load_bin_data()
		except IOError:
			print('File doesn''t exist: "'+myc.file_name+'.bin')
		myc.bintotsv()
		print('Decompiled to file: '+myc.file_name+'.txt')

	print('Folder decompiled successfully: '+folder)

def decompile_bin(file_name, binary, version, encoding='gbk'):
	print('File to decompile: '+file_name+'.bin. Binary structure to be used: '+binary.__name__)
	myc = binary(file_name, version, encoding)
	try:
		myc.load_bin_data()
	except IOError:
		print('File doesn''t exist: "'+myc.file_name+'.bin')
	myc.bintotsv()

	print('Decompiled to file: '+file_name+'.txt')

def decrypt_bin_folder(folder, version, encoding='gbk'):
	print('Folder to decrypt: '+folder)
	for c in toptablebins:
		myc = c(folder+c.__name__, version, encoding)
		try:
			myc.load_bin_data()
		except IOError:
			print('File doesn''t exist: "'+myc.file_name+'.bin')
		myc.unencrypt()
		print('Decrypted file: '+myc.file_name+'.bin')

	print('Folder decrypted successfully: '+folder)

def compile_bin_gamefolder(folder):
	print('Folder to compile: '+folder+'scripts/table/')
	cur_folder = os.getcwd()
	os.chdir(folder)
	subprocess.call(['system/game.exe','startgame','table_bin'])
	os.chdir(cur_folder)
	print('Folder compiled successfully: '+folder)

def translate_bin_folder(folder, version, folder2, version2, encoding='gbk', encoding2='gbk'): #grab data from 1, and translated names from 2.
	print('Folder to decompile: '+folder)
	for c in toptablebins:
		myc = c(folder+c.__name__, version, encoding)
		try:
			myc.load_bin_data()
		except IOError:
			print('File doesn''t exist: "'+myc.file_name+'.bin')
		
		myc2 = c(folder2+c.__name__, version2, encoding2)
		try:
			myc2.load_bin_data()
		except IOError:
			print('File doesn''t exist: "'+myc2.file_name+'.bin')
		
		#translation process:

		#if 2 ids same, copy name from second to first.
		#if second id is higher, keep the item in first.
		#if first id is higher, add the second.
		
		i=1
		j=1
		if ((myc.__class__.__name__ != 'chaticons') and (myc.__class__.__name__ != 'forgeitem') and (myc.__class__.__name__ != 'monsterinfo') and (myc.__class__.__name__ != 'serverset')):
			while (j<len(myc2.list)):
				b = myc2.list[j]
				
				if (i>=len(myc.list)):
					myc.list.append(b)
					i=i+1
					j=j+1
				else:
					a = myc.list[i]
					if a[0] == b[0]:
						if ((myc.__class__.__name__ != 'helpinfoset') and (myc.__class__.__name__ != 'musicinfo') and (myc.__class__.__name__ != 'resourceinfo') and (myc.__class__.__name__ != 'sceneffectinfo') and (myc.__class__.__name__ != 'shadeinfo') and (myc.__class__.__name__ != 'terraininfo')):
							a[1] = b[1]
						if ((myc.__class__.__name__ == 'characterinfo') or (myc.__class__.__name__ == 'hairs') or (myc.__class__.__name__ == 'helpinfoset') or (myc.__class__.__name__ == 'mapinfo') or (myc.__class__.__name__ == 'monsterlist') or (myc.__class__.__name__ == 'npclist') or (myc.__class__.__name__ == 'sceneffectinfo') or (myc.__class__.__name__ == 'sceneobjinfo') or (myc.__class__.__name__ == 'shadeinfo')):
							a[2] = b[2]
						if ((myc.__class__.__name__ == 'notifyset') or (myc.__class__.__name__ == 'sceneffectinfo')):
							a[3] = b[3]
						if ((myc.__class__.__name__ == 'monsterlist') or (myc.__class__.__name__ == 'npclist')):
							a[4] = b[4]
						if ((myc.__class__.__name__ == 'iteminfo')):
							a[93] = b[93]
						if ((myc.__class__.__name__ == 'skillinfo')):
							a[70] = b[70]
							a[71] = b[71]
							a[72] = b[72]
						i=i+1
						j=j+1
					elif a[0] > b[0]:
						myc.list.insert(i, myc2.list[j])
						j=j+1
					elif a[0] < b[0]:
						i=i+1
		i=0
		j=0

		myc.bintotsv()
		print('Translated to file: '+myc.file_name+'.txt')

	print('Folder translated successfully: '+folder)

def make_droplist(outfile):
	char_info = characterinfo()
	try:
		char_info.load_bin_data()
	except IOError:
		print('"'+char_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	char_info.bintotsv()

	item_info = iteminfo()
	try:
		item_info.load_bin_data()
	except IOError:
		print('"'+item_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	item_info.bintotsv()
	
	file = open(outfile, 'w', encoding=toptableencoding, errors='ignore')
	
	all_itemdroprates = []

	for i,v in enumerate(item_info.list):
		if i != 0:
			item_id = int(v[0])
			item_name = str(v[1])
			item_droprates = []
			
			for j,w in enumerate(char_info.list):
				if j != 0:
					char_name = str(w[1])
					print(j)
					char_dropitems = unjop(w[46])
					char_dropitemrates = unjop(w[47])
					
					for k,x in enumerate(char_dropitems[0]):
						if item_id == int(x):
							t_droprate = 0
							try:
								t_droprate = round(10000/int(char_dropitemrates[0][k]),6)
							except ZeroDivisionError:
								t_droprate = 10000
							except IndexError:
								t_droprate = 10000/4294967295
							item_droprates.append((char_name,t_droprate))
							break
			item_droprates.sort(key=lambda a: a[1], reverse=True)
			all_itemdroprates.append((item_name, item_droprates))
	
	all_itemdroprates.sort(key=lambda a: str.lower(a[0]))
	
	i = 0
	for item_name, item_droprates in all_itemdroprates:
		if item_droprates != []:
			if i != 0:
				file.write('\n')
			file.write(item_name + ": ")
			for j,w in enumerate(item_droprates):
				if j == 0:
					file.write(w[0] + "(" + str(w[1]) + "%)")
				else:
					file.write(", " + w[0] + "(" + str(w[1]) + "%)")
			i = i + 1
	file.close()

def make_cha_droplist(outfile):
	char_info = characterinfo()
	try:
		char_info.load_bin_data()
	except IOError:
		print('"'+char_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	char_info.bintotsv()

	item_info = iteminfo()
	try:
		item_info.load_bin_data()
	except IOError:
		print('"'+item_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	item_info.bintotsv()
	
	file = open(outfile, 'w', encoding=toptableencoding, errors='ignore')
	
	all_chardroprates = []
	
	for i,v in enumerate(char_info.list):
		if i != 0:
			char_name = str(v[1])
			char_dropitems = unjop(v[46])
			char_dropitemrates = unjop(v[47])
			char_droprates = []
			
			for j,w in enumerate(char_dropitems[0]):
				item_name = ""
				item_id = int(w)
				for k,x in enumerate(item_info.list):
					if item_id == 0:
						break
					if k != 0:
						if item_id == int(x[0]):
							item_name = str(x[1])
							break
				if item_name == "":
					break
				t_droprate = 0
				try:
					t_droprate = round(10000/int(char_dropitemrates[0][j]),6)
				except ZeroDivisionError:
					t_droprate = 10000
				except IndexError:
					t_droprate = 10000/4294967295
				
				char_droprates.append((item_name,t_droprate))
			char_droprates.sort(key=lambda a: a[1], reverse=True)
			all_chardroprates.append((char_name, char_droprates))
	all_chardroprates.sort(key=lambda a: str.lower(a[0]))

	i = 0
	for char_name, char_droprates in all_chardroprates:
		if char_droprates != []:
			if i != 0:
				file.write('\n')
			file.write(char_name + ": ")
			for j,w in enumerate(char_droprates):
				if j == 0:
					file.write(w[0] + "(" + str(w[1]) + "%)")
				else:
					file.write(", " + w[0] + "(" + str(w[1]) + "%)")
			i = i + 1
	file.close()

def fixskillscripts():
	for c in toptablebins:
		myc = c()
		try:
			myc.load_bin_data()
		except IOError:
			print('"'+myc.file_name+'.bin'+'" doesn''t exist, skipping...')

		if ((myc.__class__.__name__ == 'skillinfo')):
			file = open(toptablefolder + 'skillinfo.funcs.txt', 'wt', encoding=toptableencoding)
			for line_number, data in enumerate(myc.list):
				if line_number != 0:
					mydata = list(data)
					
					mylist = list(range(22,32))
					mylist[len(mylist):len(mylist)] = [44]
					
					for function_effect_id in mylist:
						if (mydata[function_effect_id] != '0'):
							params1 = 'l'
							params2 = 'l'
							event_number = function_effect_id-22
							if (event_number == 22): #44-22
								event_number = 10
							
							if (event_number == 7):
								params1 = 'a,d,l'
								params2 = 'l,a,d'
							if ((event_number == 6) or (event_number == 8) or (event_number == 9)):
								params1 = 'a,l'
								params2 = 'l,a'
							file.write('function '+'Skill_'+str(mydata[0])+'_'+str(event_number)+'('+params1+')\treturn skill(0,'+str(mydata[0])+','+str(event_number)+','+params2+') end	--'+mydata[function_effect_id]+'\n')

							mydata[function_effect_id] = 'Skill_'+str(mydata[0])+'_'+str(event_number)
					mydata = tuple(mydata)
					
					myc.list[line_number] = mydata
			file.close()

		if ((myc.__class__.__name__ == 'skilleff')):
			file = open(toptablefolder + 'skilleff.funcs.txt', 'wt', encoding=toptableencoding)
			for line_number, data in enumerate(myc.list):
				if line_number != 0:
					mydata = list(data)
					for function_effect_id in list(range(3,6)):
						if (mydata[function_effect_id] != '0'):
							params1 = 'l'
							params2 = 'l'
							event_number = function_effect_id-3

							if ((event_number == 1) or (event_number == 2)):
								params1 = 'a,l'
								params2 = 'l,a'
							file.write('function '+'Skill_Effect_'+str(mydata[0])+'_'+str(event_number)+'('+params1+')\treturn skill(1,'+str(mydata[0])+','+str(event_number)+','+params2+') end	--'+mydata[function_effect_id]+'\n')

							mydata[function_effect_id] = 'Skill_Effect_'+str(mydata[0])+'_'+str(event_number)
					mydata = tuple(mydata)
					
					myc.list[line_number] = mydata
			file.close()

		if ((myc.__class__.__name__ == 'iteminfo')):
			file = open(toptablefolder + 'iteminfo.funcs.txt', 'wt', encoding=toptableencoding)
			for line_number, data in enumerate(myc.list):
				if line_number != 0:
					mydata = list(data)
					function_effect_id = 86
					if (mydata[function_effect_id] != '0'):
						params1 = 'p,i'
						params2 = 'p,i'
						file.write('function '+'Item_Skill_'+str(mydata[0])+'('+params1+')\treturn skill(2,'+str(mydata[0])+',0,0,'+params2+') end	--'+mydata[function_effect_id]+'\n')

						mydata[function_effect_id] = 'Item_Skill_'+str(mydata[0])
					mydata = tuple(mydata)
					
					myc.list[line_number] = mydata
			file.close()

		myc.bintotsv()

	print('Finished successfully.')

'''
for c in toptablebins:
	myc = c()
	try:
		myc.load_bin_data()
	except IOError:
		print('"'+myc.file_name+'.bin'+'" doesn''t exist, skipping...')

	if ((myc.__class__.__name__ == 'iteminfo')):
		file = open(toptablefolder + 'iteminfo.books.txt', 'wt', encoding=toptableencoding)
		for line_number, data in enumerate(myc.list):
			if line_number != 0:
				mydata = list(data)
				id_id = 0
				name_id = 1
				item_type_id = 10
				
				if (mydata[item_type_id] == '34'):
					file.write('skills[ITEM_SKILL]['+mydata[id_id]+'][0] = function(s) itemskill_learnplayerskillbook(s, SK_'+mydata[name_id]+') end\n')
				mydata = tuple(mydata)
				
				myc.list[line_number] = mydata
		file.close()
	myc.bintotsv()

print('Finished successfully.')
'''

'''
for c in toptablebins:
	myc = c()
	try:
		myc.load_bin_data()
	except IOError:
		print('"'+myc.file_name+'.bin'+'" doesn''t exist, skipping...')
	myc.bintotsv()

	if (myc.file_name == 'iteminfo'):
		equip_list = []
		#print(myc.list[1])
		for i, a in enumerate(myc.list):
			if (i!=0):
				if (a[28].split(',')[0] != '-1'):
					myitem = []
					myitem.append(a[1])
					myitem.append(a[0])
					myitem.append(a[10])
					for x in a[28].split(',')[0:2]:
						if (x=='-2'):
							x=''
						myitem.append(x)
					myitem.append(a[24])
					for x in a[23].split(',')[0:4]:
						if ((x=='-1') or (x=='-2')):
							x=''
						myitem.append(x)
					for x in a[25].split(',')[0:19]:
						if ((x=='-1') or (x=='-2')):
							x=''
						myitem.append(x)

					myitem.append(a[31])
					myitem.append(a[32])
					myitem.append(a[33])
					myitem.append(a[34])
					myitem.append(a[35])
					myitem.append(a[36])
					myitem.append(a[42])
					myitem.append(a[43])
					myitem.append(a[39])
					myitem.append(a[40])
					myitem.append(a[41])
					myitem.append(a[45])
					myitem.append(a[44])
					myitem.append(a[47])
					myitem.append(a[46])
					myitem.append(a[48])
					myitem.append(a[49])
					myitem.append(a[37])
					myitem.append(a[50])

					myitem.append(a[52].split(',')[0])
					myitem.append(a[52].split(',')[1])
					myitem.append(a[53].split(',')[0])
					myitem.append(a[53].split(',')[1])
					myitem.append(a[54].split(',')[0])
					myitem.append(a[54].split(',')[1])
					myitem.append(a[55].split(',')[0])
					myitem.append(a[55].split(',')[1])
					myitem.append(a[56].split(',')[0])
					myitem.append(a[56].split(',')[1])
					myitem.append(a[57].split(',')[0])
					myitem.append(a[57].split(',')[1])
					myitem.append(a[63].split(',')[0])
					myitem.append(a[63].split(',')[1])
					myitem.append(a[64].split(',')[0])
					myitem.append(a[64].split(',')[1])
					myitem.append(a[60].split(',')[0])
					myitem.append(a[60].split(',')[1])
					myitem.append(a[61].split(',')[0])
					myitem.append(a[61].split(',')[1])
					myitem.append(a[62].split(',')[0])
					myitem.append(a[62].split(',')[1])
					myitem.append(a[72].split(',')[0])
					myitem.append(a[72].split(',')[1])
					myitem.append(a[66].split(',')[0])
					myitem.append(a[66].split(',')[1])
					myitem.append(a[65].split(',')[0])
					myitem.append(a[65].split(',')[1])
					myitem.append(a[68].split(',')[0])
					myitem.append(a[68].split(',')[1])
					myitem.append(a[67].split(',')[0])
					myitem.append(a[67].split(',')[1])
					myitem.append(a[69].split(',')[0])
					myitem.append(a[69].split(',')[1])
					myitem.append(a[70].split(',')[0])
					myitem.append(a[70].split(',')[1])
					myitem.append(a[58].split(',')[0])
					myitem.append(a[58].split(',')[1])
					myitem.append(a[71].split(',')[0])
					myitem.append(a[71].split(',')[1])

					equip_list.append(myitem)
		
		file = open(toptablefolder + 'iteminfo.equip.txt', 'wt', encoding=toptableencoding)
		for i,a in enumerate(equip_list):
			a=list(a)
			if (i==0):
				file.write('\t'.join(a))
			else:
				file.write('\n'+'\t'.join(a))
		file.close()

	if (myc.file_name == 'iteminfo'):
		equip_list = []
		#for i, a in myc.list:
		#	if (item[24] != '0'):
		#		equip_list.append([a[1],])
		
		file = open(toptablefolder + 'iteminfo.equip.txt', 'wt', encoding=toptableencoding)
		for i,a in enumerate(equip_list):
			a=list(a)
			if (i==0):
				file.write('//'+'\t'.join(a))
			else:
				file.write('\n'+'\t'.join(a))
		file.close()
'''

'''
def unjop(s):
	result = s.split(";")
	for i,v in enumerate(result):
		result[i] = s.split(",")
	return result

#TODO: improve drasticly these algorithms

from collections import OrderedDict

def make_itemmodellist(outfile):
	item_info = iteminfo()
	try:
		item_info.load_bin_data()
	except IOError:
		print('"'+item_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	item_info.bintotsv()
	
	file = open(outfile, 'w', encoding=toptableencoding, errors='ignore')
	
	all_modelitems = OrderedDict()

	for i,v in enumerate(item_info.list):
		if i != 0:
			item_id = int(v[0])
			item_name = str(v[1])
			item_modellance = str(v[4])
			item_modelcarsise = str(v[5])
			item_modelphyllis = str(v[6])
			item_modelami = str(v[7])
			
			try:
				all_modelitems[item_modellance].append(item_name + ' (Lance)')
			except KeyError:
				all_modelitems[item_modellance] = []
				all_modelitems[item_modellance].append(item_name + ' (Lance)')

			try:
				all_modelitems[item_modelcarsise].append(item_name + ' (Carsise)')
			except KeyError:
				all_modelitems[item_modelcarsise] = []
				all_modelitems[item_modelcarsise].append(item_name + ' (Carsise)')
			
			try:
				all_modelitems[item_modelphyllis].append(item_name + ' (Phyllis)')
			except KeyError:
				all_modelitems[item_modelphyllis] = []
				all_modelitems[item_modelphyllis].append(item_name + ' (Phyllis)')
			
			try:
				all_modelitems[item_modelami].append(item_name + ' (Ami)')
			except KeyError:
				all_modelitems[item_modelami] = []
				all_modelitems[item_modelami].append(item_name + ' (Ami)')
	
	all_modelitems = sorted(all_modelitems.items(), key=lambda t: t[0])
	
	i = 0
	for model, item_names in all_modelitems:
		if model != '0':
			if i != 0:
				file.write('\n')
			file.write(model + ": ")
			for j,w in enumerate(item_names):
				if j == 0:
					file.write(w)
				else:
					file.write(", " + w)
			i = i + 1
	file.close()
'''

def unjop(s):
	result = s.split(";")
	for i,v in enumerate(result):
		result[i] = s.split(",")
	return result

def make_droplist(outfile):
	char_info = characterinfo()
	try:
		char_info.load_bin_data()
	except IOError:
		print('"'+char_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	char_info.bintotsv()

	item_info = iteminfo()
	try:
		item_info.load_bin_data()
	except IOError:
		print('"'+item_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	item_info.bintotsv()
	
	file = open(outfile, 'w', encoding=toptableencoding, errors='ignore')
	
	all_itemdroprates = []

	for i,v in enumerate(item_info.list):
		if i != 0:
			item_id = int(v[0])
			item_name = str(v[1])
			item_droprates = []
			
			for j,w in enumerate(char_info.list):
				if j != 0:
					char_name = str(w[1])
					print(j)
					char_dropitems = unjop(w[46])
					char_dropitemrates = unjop(w[47])
					
					for k,x in enumerate(char_dropitems[0]):
						if item_id == int(x):
							t_droprate = 0
							try:
								t_droprate = round(10000/int(char_dropitemrates[0][k]),6)
							except ZeroDivisionError:
								t_droprate = 10000
							except IndexError:
								t_droprate = 10000/4294967295
							item_droprates.append((char_name,t_droprate))
							break
			item_droprates.sort(key=lambda a: a[1], reverse=True)
			all_itemdroprates.append((item_name, item_droprates))
	
	all_itemdroprates.sort(key=lambda a: str.lower(a[0]))
	
	i = 0
	for item_name, item_droprates in all_itemdroprates:
		if item_droprates != []:
			if i != 0:
				file.write('\n')
			file.write(item_name + ": ")
			for j,w in enumerate(item_droprates):
				if j == 0:
					file.write(w[0] + "(" + str(w[1]) + "%)")
				else:
					file.write(", " + w[0] + "(" + str(w[1]) + "%)")
			i = i + 1
	file.close()

def make_cha_droplist(outfile):
	char_info = characterinfo()
	try:
		char_info.load_bin_data()
	except IOError:
		print('"'+char_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	char_info.bintotsv()

	item_info = iteminfo()
	try:
		item_info.load_bin_data()
	except IOError:
		print('"'+item_info.file_name+'.bin'+'" doesn''t exist, skipping...')
	item_info.bintotsv()
	
	file = open(outfile, 'w', encoding=toptableencoding, errors='ignore')
	
	all_chardroprates = []
	
	for i,v in enumerate(char_info.list):
		if i != 0:
			char_name = str(v[1])
			char_dropitems = unjop(v[46])
			char_dropitemrates = unjop(v[47])
			char_droprates = []
			
			for j,w in enumerate(char_dropitems[0]):
				item_name = ""
				item_id = int(w)
				for k,x in enumerate(item_info.list):
					if item_id == 0:
						break
					if k != 0:
						if item_id == int(x[0]):
							item_name = str(x[1])
							break
				if item_name == "":
					break
				t_droprate = 0
				try:
					t_droprate = round(10000/int(char_dropitemrates[0][j]),6)
				except ZeroDivisionError:
					t_droprate = 10000
				except IndexError:
					t_droprate = 10000/4294967295
				
				char_droprates.append((item_name,t_droprate))
			char_droprates.sort(key=lambda a: a[1], reverse=True)
			all_chardroprates.append((char_name, char_droprates))
	all_chardroprates.sort(key=lambda a: str.lower(a[0]))

	i = 0
	for char_name, char_droprates in all_chardroprates:
		if char_droprates != []:
			if i != 0:
				file.write('\n')
			file.write(char_name + ": ")
			for j,w in enumerate(char_droprates):
				if j == 0:
					file.write(w[0] + "(" + str(w[1]) + "%)")
				else:
					file.write(", " + w[0] + "(" + str(w[1]) + "%)")
			i = i + 1
	file.close()

#from os.path import join, getsize
#for root, dirs, files in os.walk('.'):
#	if(root == '.'):
#		for filename in files:
#			if (filename[-4:] == ".bin"):
#				print(filename)


#key for sql inventory/bank/tempinv: 31 39 38 30 30 32 31 36 31, same decryption method.

import re

def make_res():
	res = []
	areaset_list = []
	mapinfo_list = []
	color_list = []
	for c in toptablebins:
		myc = c()
		try:
			myc.load_bin_data()
		except IOError:
			print('"'+myc.file_name+'.bin'+'" doesn''t exist, skipping...')
	#translation process:

	#if 2 ids same, copy name from second to first.
	#if second id is higher, keep the item in first.
	#if first id is higher, add the second.
		
		i=1
		j=1
		
		print(myc.file_name)
		#TABLE_characterinfo_TXT_N_1356#
		if ((myc.__class__.__name__ != 'chaticons') and (myc.__class__.__name__ != 'forgeitem') and (myc.__class__.__name__ != 'monsterinfo')):
			while (i<len(myc.list)):
				if (myc.__class__.__name__ == 'areaset'):
					areaset_list.append(myc.list[i][:])
				if (myc.__class__.__name__ == 'mapinfo'):
					mapinfo_list.append(myc.list[i][:])
				
				a = myc.list[i]
				if ((myc.__class__.__name__ != 'helpinfoset') and (myc.__class__.__name__ != 'mapinfo') and (myc.__class__.__name__ != 'musicinfo') and (myc.__class__.__name__ != 'resourceinfo') and (myc.__class__.__name__ != 'sceneffectinfo') and (myc.__class__.__name__ != 'sceneobjinfo') and (myc.__class__.__name__ != 'shadeinfo') and (myc.__class__.__name__ != 'terraininfo')):
					res.append(('T_'+myc.__class__.__name__+'_TXT_'+str(a[0]),a[1]))
					a[1] = ('#T_'+myc.__class__.__name__+'_TXT_'+str(a[0])+'#').upper()
					if (myc.__class__.__name__ == 'characterinfo'):
						a[2] = ('#T_'+myc.__class__.__name__+'_TXT_'+str(a[0])+'#').upper()
				
				if ((myc.__class__.__name__ == 'hairs')):
					temp = 1
					for j,v in enumerate(color_list):
						if (v[1] == a[2]):
							temp = 0
							a[2] = '#T_COLOR_'+str(j)+'#'
					if temp == 1:
						color_list.append(('T_COLOR_'+str(len(color_list)),a[2]))
						res.append(('T_COLOR_'+str(len(color_list)-1),a[2]))
						a[2] = '#T_COLOR_'+str(len(color_list)-1)+'#'
				
				if (myc.__class__.__name__ == 'sceneffectinfo'):
					res.append(('T_sei_'+str(a[0]),a[2]))
					a[2] = ('#T_sei_'+str(a[0])+'#').upper()
					res.append(('T_seiD_'+str(a[0]),a[3]))
					a[3] = ('#T_seiD_'+str(a[0])+'#').upper()
					
				if (myc.__class__.__name__ == 'shadeinfo'):
					res.append(('T_si_'+str(a[0]),a[2]))
					a[2] = ('#T_si_'+str(a[0])+'#').upper()
					
				if (myc.__class__.__name__ == 'mapinfo'):
					res.append(('T_mi_'+str(a[0]),a[2]))
					a[2] = ('#T_mi_'+str(a[0])+'#').upper()
					
				if (myc.__class__.__name__ == 'sceneobjinfo'):
					res.append(('T_soi_'+str(a[0]),a[2]))
					a[2] = ('#T_soi_'+str(a[0])+'#').upper()
				
				if ((myc.__class__.__name__ == 'monsterlist') or (myc.__class__.__name__ == 'npclist')):
					for j,v in enumerate(mapinfo_list):
						if (a[4][:15] == v[2]):
							a[4] = ('#T_mi_'+str(v[0])+'#').upper()
							break
				if (myc.__class__.__name__ == 'npclist'):
					temp = 1
					for j,v in enumerate(areaset_list):
						if (a[2] == v[1]):
							temp = 0
							a[2] = ('#T_AREASET_TXT_'+str(v[0])+'#').upper()
							break
					if temp == 1:
						for j,v in enumerate(mapinfo_list):
							if (a[2][:15] == v[2]):
								temp = 0
								a[2] = ('#T_mi_'+str(v[0])+'#').upper()
								break
				
				if ((myc.__class__.__name__ == 'iteminfo')):
					res.append(('T_'+myc.__class__.__name__+'_TXT_D_'+str(a[0]),a[93]))
					a[93] = ('#T_'+myc.__class__.__name__+'_TXT_D_'+str(a[0])+'#').upper()
				
				if ((myc.__class__.__name__ == 'skillinfo')):
					res.append(('T_'+myc.__class__.__name__+'_TXT_D_'+str(a[0]),a[70]))
					a[70] = ('#T_'+myc.__class__.__name__+'_TXT_D_'+str(a[0])+'#').upper()
					res.append(('T_'+myc.__class__.__name__+'_TXT_F_'+str(a[0]),a[71]))
					a[71] = ('#T_'+myc.__class__.__name__+'_TXT_F_'+str(a[0])+'#').upper()
					res.append(('T_'+myc.__class__.__name__+'_TXT_U_'+str(a[0]),a[72]))
					a[72] = ('#T_'+myc.__class__.__name__+'_TXT_U_'+str(a[0])+'#').upper()
				i=i+1
		i=0
		myc.bintotsv()
		
	file = open('C:/Utenti/Alen/Desktop/res.txt', 'w', encoding=toptableencoding, errors='ignore')
	while (i<len(res)):

		file.write(res[i][0].upper()+' { "'+re.sub(r'([\"])', r'\\\1', re.sub(r'\\\"', r'"', res[i][1]))+'" }\n')
		i=i+1
	file.close()
		
	print('Finished successfully.')

#########################
# Configuration section #
#########################
#Version history:
#2.5 PKO: +4 bytes to skilleff.bin (2 of those added to the end instead of next to the name, like the other 2 versions).
#2.5 KOP: +4 bytes to skilleff.bin, all files encrypted, can compile ResourceInfo.
#2.5 TOP: +4 bytes to skilleff.bin and skillinfo.bin, all files encrypted, can compile ResourceInfo.

#2.4 server: 2.4 with -8 bytes on characterinfo.
#2.4: +4 equipment slots, +4 item switch locations (8 bytes), +monsterinfo added, +encryption of magicsingleinfo, magicgroupinfo, resourceinfo, terraininfo.

#2.0: all: Too many changes to list, but most important is helpinfoset, monsterlist, and npclist added, stringset replaced with the .res file in the system folder.
#1.38: all: added chasf to characterinfo (and many extra bytes), and fix shipinfo/shipiteminfo id being +1 than should be. Base version.
#1.35: all: Earliest version supported.

#Version numbers:
#8 for PKO v2.5 (latest).
#7 for KOP v2.5 (latest).
#6 for TOP v2.5 (latest).
#5 for PKO v2.4 server only (decompiling server bins will result in resolved resource strings, which can then be used on other versions).
#4 for PKO v2.4 (used by the newer v2 servers).
#3 for TOP v2.0 (used by all older v2 servers).
#2 for TOP v1.38 (latest).
#1 for TOP v1.35 (used by a couple of servers).

#decompile_bin_folder('C:/Decompiler/PKO1.38/table/', 2, encoding='gbk')
#decompile_bin_folder('C:/Games/TOP2.5/scripts/table/', 6, encoding='gbk')
#decompile_bin_folder('C:/Games/PKO2.5/scripts/table/', 8)
#decompile_bin_folder('C:/Games/KOP2.5/scripts/table/', 7)
decompile_bin_folder('C:/Decompiler/PKO2.4/table/', 4)
#compile_bin_gamefolder('C:/Games/TOP/')

#decrypt_bin_folder('C:/Games/TOP2.5/scripts/table/', 6, encoding='gbk')
#decrypt_bin_folder('C:/Games/PKO2.5/scripts/table/', 8, encoding='gbk')

#decompile_bin('C:/Games/TOP2.5/scripts/table/sceneffectinfo', sceneffectinfo, 6, encoding='gbk') #without ".bin"
#decompile_bin('C:/Games/TOP2.5/scripts/table/characterinfo', characterinfo, 6, encoding='gbk') #without ".bin"
#decompile_bin('C:/Games/TOP2.5/scripts/table/serverset', serverset, 6, encoding='gbk') #without ".bin"

#translate_bin_folder('C:/Games/PKO2.5/scripts/table/', 8, 'C:/Games/TOP2.5/scripts/table/', 6)
#make_res()
#remember, need to compile before doing the next translation
#compile_bin_gamefolder('C:/Games/PKO2.5/')

#translate_bin_folder('C:/Games/KOP2.5/scripts/table/', 7, 'C:/Games/PKO2.5/scripts/table/', 8)
#make_res()
#translate_bin_folder('C:/Games/KOP2.5/scripts/table/', 7, 'C:/Games/TOP2.5/scripts/table/', 6)
#make_res()

#toptablefolder = 'C:/Games/PKO2.4/scripts/table/'
#toptableversion = 4

#make_itemmodelsunique(1)
#automatically fix skill scripts (needed because of adjustments in skillinfo - compile before doing this)
#fixskillscripts()
#make_cha_droplist("C:/Games (x86)/TOP/rzo2/scripts/table/chardroplist.txt")
#make_droplist("C:/Games (x86)/TOP/rzo2/scripts/table/itemdroplist.txt")
#make_res()

################################
# End of configuration section #
################################

 

Edited by Lucky

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...