summaryrefslogtreecommitdiff
path: root/hercules/code/servertoclient
diff options
context:
space:
mode:
Diffstat (limited to 'hercules/code/servertoclient')
-rw-r--r--hercules/code/servertoclient/__init__.py0
-rw-r--r--hercules/code/servertoclient/groups.py185
-rw-r--r--hercules/code/servertoclient/homunculuses.py31
-rw-r--r--hercules/code/servertoclient/items.py138
-rw-r--r--hercules/code/servertoclient/luas.py51
-rw-r--r--hercules/code/servertoclient/maps.py48
-rw-r--r--hercules/code/servertoclient/mercenaries.py31
-rw-r--r--hercules/code/servertoclient/monsters.py43
-rw-r--r--hercules/code/servertoclient/npcs.py29
-rw-r--r--hercules/code/servertoclient/pets.py31
-rw-r--r--hercules/code/servertoclient/quests.py39
-rw-r--r--hercules/code/servertoclient/skills.py33
-rw-r--r--hercules/code/servertoclient/sprites.py467
13 files changed, 1126 insertions, 0 deletions
diff --git a/hercules/code/servertoclient/__init__.py b/hercules/code/servertoclient/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hercules/code/servertoclient/__init__.py
diff --git a/hercules/code/servertoclient/groups.py b/hercules/code/servertoclient/groups.py
new file mode 100644
index 0000000..99424e5
--- /dev/null
+++ b/hercules/code/servertoclient/groups.py
@@ -0,0 +1,185 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2017 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+from code.fileutils import makeDir, readFile, saveFile
+
+nameSplit = re.compile(":")
+comaSplit = re.compile(",")
+
+class Groups:
+ pass
+
+def readLine(f):
+ for line in f:
+ if len(line) == 0:
+ continue
+ if line[-1:] == "\n":
+ line = line[:-1]
+ idx = line.find("/*")
+ if idx >= 0:
+ line = line[:idx]
+ line = line.strip()
+ yield line
+
+def skipFor(data, f):
+ for line in readLine(f):
+ if line == data or line == data + "\n":
+ return True
+ return False
+
+def readCommands(f):
+ commands = dict()
+ for line in readLine(f):
+ if line == "}":
+ return commands
+ parts = nameSplit.split(line)
+ if len(parts) != 2:
+ continue
+ name = parts[0].strip()
+ value = parts[1].strip()
+ idx1 = value.find("[")
+ if idx1 < 0:
+ commands[name] = (value, "false")
+ else:
+ idx2 = value.find("]")
+ value = value[idx1 + 1: idx2 - idx1]
+ parts = comaSplit.split(value)
+ commands[name] = (parts[0].strip(), parts[1].strip())
+ print "command: {0}, {1}".format(name, commands[name])
+ return commands
+
+def readPermissions(f):
+ permissions = dict()
+ for line in readLine(f):
+ if line == "}":
+ return permissions
+ parts = nameSplit.split(line)
+ if len(parts) != 2:
+ continue
+ name = parts[0].strip()
+ value = parts[1].strip()
+ permissions[name] = value
+ print "permission: {0}, {1}".format(name, value)
+ return permissions
+
+def readInherit(data):
+ inherit = set()
+ idx1 = data.find("(")
+ idx2 = data.find(")")
+ data = data[idx1 + 1: idx2 - idx1]
+ parts = comaSplit.split(data)
+ for field in parts:
+ field = field.strip()
+ if field == "":
+ continue
+ inherit.add(field)
+ return inherit
+
+def readGroup(groups, f):
+ fields = dict()
+ commands = dict()
+ permissions = dict()
+ inherit = set()
+ for line in readLine(f):
+ if line == "}" or line == "},":
+ groups.nameToId[fields["name"]] = fields["id"]
+ groups.idToFields[fields["id"]] = fields
+ groups.idToCommands[fields["id"]] = commands
+ groups.idToPermissions[fields["id"]] = permissions
+ groups.idToInherit[fields["id"]] = inherit
+ groups.idToNames[fields["id"]] = fields["name"]
+ return
+ parts = nameSplit.split(line)
+ if len(parts) != 2:
+ continue
+ name = parts[0].strip()
+ value = parts[1].strip()
+ print "line: {0}, {1}".format(name, value)
+ if name == "id":
+ fields["id"] = value
+ elif name == "name":
+ fields["name"] = value
+ elif name == "commands":
+ commands = readCommands(f)
+ print "Commands: {0}".format(commands)
+ elif name == "permissions":
+ permissions = readPermissions(f)
+ print "Permissions: {0}".format(permissions)
+ elif name == "inherit":
+ inherit = readInherit(value)
+ print "Inherit: {0}".format(inherit)
+
+def getCommandType(data):
+ if data[0] == "false" and data[1] == "false":
+ return "false"
+ elif data[0] == "false" and data[1] == "true":
+ return "other";
+ elif data[0] == "true" and data[1] == "false":
+ return "self"
+ elif data[0] == "true" and data[1] == "true":
+ return "both"
+
+def getCommandsStr(commands):
+ data = ""
+ commandFormat = "\n <command name=\"{0}\" use=\"{1}\" />"
+ for command in commands:
+ data = data + commandFormat.format(
+ command,
+ getCommandType(commands[command])
+ )
+ return data
+
+def getPermissionsStr(permissions):
+ data = ""
+ permissionFormat = "\n <permission name=\"{0}\" />"
+ for permission in permissions:
+ data = data + permissionFormat.format(
+ permission
+ )
+ return data
+
+def getInheritStr(inherits, names):
+ data = ""
+ if len(inherits) == 0:
+ return ""
+ for name in inherits:
+ if data != "":
+ data = data + ","
+ data += names[name]
+ return "\n inherit=\"{0}\"".format(data)
+
+def convertGroups():
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ groupsConfFile = "serverdata/conf/groups.conf"
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "group.tpl")
+ groupsTpl = readFile(templatesDir + "groups.xml")
+ groups = Groups()
+ groups.nameToId = dict()
+ groups.idToFields = dict()
+ groups.idToCommands = dict()
+ groups.idToPermissions = dict()
+ groups.idToNames = dict()
+ groups.idToInherit = dict()
+
+ with open(groupsConfFile, "r") as f:
+ skipFor("groups: (", f)
+ while (skipFor("{", f) == True):
+ readGroup(groups, f)
+
+ data = ""
+ for ids in sorted(groups.idToFields):
+ data = data + tpl.format(
+ id = ids,
+ name = groups.idToNames[ids],
+ inherit = getInheritStr(groups.idToInherit[ids], groups.nameToId),
+ commands = getCommandsStr(groups.idToCommands[ids]),
+ permissions = getPermissionsStr(groups.idToPermissions[ids]),
+ )
+
+ saveFile(destDir + "groups.xml", groupsTpl.format(data))
diff --git a/hercules/code/servertoclient/homunculuses.py b/hercules/code/servertoclient/homunculuses.py
new file mode 100644
index 0000000..678a96c
--- /dev/null
+++ b/hercules/code/servertoclient/homunculuses.py
@@ -0,0 +1,31 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+from code.fileutils import makeDir, readFile, saveFile
+
+def convertHomunculuses():
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ homunculusesDbFile = "serverdata/db/re/homunculus_db.txt"
+ fieldsSplit = re.compile(",")
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "homunculus.tpl")
+ homunculuses = readFile(templatesDir + "homunculuses.xml")
+ data = ""
+ homunculusSprite = "<sprite>monsters/tortuga.xml</sprite>";
+ with open(homunculusesDbFile, "r") as f:
+ for line in f:
+ if line == "" or line[0:2] == "//":
+ continue
+ rows = fieldsSplit.split(line)
+ if len(rows) < 9:
+ continue
+ data = data + tpl.format(
+ id = rows[0],
+ sprite = homunculusSprite,
+ name = rows[2])
+ saveFile(destDir + "homunculuses.xml", homunculuses.format(data))
diff --git a/hercules/code/servertoclient/items.py b/hercules/code/servertoclient/items.py
new file mode 100644
index 0000000..3fdb531
--- /dev/null
+++ b/hercules/code/servertoclient/items.py
@@ -0,0 +1,138 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+from sets import Set
+
+from code.fileutils import makeDir, readFile, saveFile
+from code.stringutils import stripQuotes2, strToXml
+
+def prepStat(val, text):
+ if val != "0" and val != "":
+ return " {0}=\"{1}\"\n".format(text, val)
+ return ""
+
+def convertItems():
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ itemsDbFile = "serverdata/sql-files/item_db_re.sql"
+ fieldsSplit = re.compile(",")
+ bracketsSplit = re.compile("[(]|[)]")
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "item.tpl")
+ items = readFile(templatesDir + "items.xml")
+ data = ""
+ ids = Set()
+ with open(itemsDbFile, "r") as f:
+ for line in f:
+ if len(line) < 10 or line[0:2] == "//" or line[0:12] != "REPLACE INTO":
+ continue
+ rows = bracketsSplit.split(line)
+ if len(rows) < 2:
+ continue
+ rows = fieldsSplit.split(rows[1])
+ if len(rows) < 31:
+ continue
+ rows = stripQuotes2(rows)
+ itemId = rows[0]
+ name = rows[1]
+# name2 = rows[2]
+ itemType = rows[3]
+# priceBuy = rows[4]
+# priceSell = rows[5]
+ weight = rows[6]
+ atk = rows[7]
+ matk = rows[8]
+ defense = rows[9]
+ attackRange = rows[10]
+# slots = rows[11]
+# equipJobs = rows[12]
+# equipUpper = rows[12]
+# equipGender = rows[14]
+ equipLocations = rows[15]
+# weaponLevel = rows[16]
+# equipLevelMin = rows[17]
+# equipLevelMax = rows[18]
+# refinable = rows[19]
+ view = rows[20]
+# bindOnEquip = rows[21]
+# buyInStore = rows[22]
+ delay = rows[23]
+# tradeFlag = rows[24]
+# tradeGroup = rows[25]
+# nouseFlag = rows[26]
+# nouseGroup = rows[27]
+# stackAmount = rows[28]
+# stackFlag = rows[29]
+# sprite = rows[30]
+
+ name = name.replace("\\'", "'")
+ image = ""
+
+ statStr = prepStat(atk, "attack")
+ statStr = statStr + prepStat(matk, "mattack")
+ statStr = statStr + prepStat(defense, "defense")
+ statStr = statStr + prepStat(weight, "weight")
+ statStr = statStr + prepStat(attackRange, "range")
+ statStr = statStr + prepStat(delay, "speed")
+# print itemId + "," + equipLocations
+# typeStr = "other"
+ typeStr = "equip-legs"
+ spriteStr = "equipment/legs/trousers-male.xml"
+ image = "generic/box-fish.png"
+ if itemType == 0 or itemType == 2 or itemType == 18: # usable
+ image = "usable/bread.png"
+ typeStr = "usable"
+ spriteStr = "";
+ elif equipLocations == "0":
+ image = "usable/bread.png"
+ typeStr = "usable"
+ spriteStr = "";
+ elif equipLocations == "1":
+ image = "equipment/legs/shorts.png|S:#4d4d4d,514d47,686868,706662,919191,99917b,b6b6b6,c0b698,dfdfdf,e4dfca"
+ typeStr = "equip-legs"
+ spriteStr = "equipment/legs/shorts-male.xml|#4d4d4d,514d47,686868,706662,919191,99917b,b6b6b6,c0b698,dfdfdf,e0d5bf";
+ elif equipLocations == "2":
+ image = "equipment/weapons/knife.png"
+ typeStr = "equip-1hand"
+ spriteStr = "equipment/weapons/knife.xml";
+ elif equipLocations == "4":
+ image = "equipment/hands/armbands.png"
+ typeStr = "equip-arms"
+ spriteStr = "equipment/hands/armbands-male.xml";
+ elif equipLocations == "16":
+ image = "equipment/chest/cottonshirt.png|S:#3c3c3c,3e3c38,4d4d4d,514d47,686868,706662,919191,99917b,b6b6b6,c0b698,dfdfdf,e4dfca"
+ typeStr = "equip-torso"
+ spriteStr = "equipment/chest/cottonshirt-male.xml|#43413d,59544f,7a706c,8a8176,a69e88,d1c7a7,e0d5bf";
+ elif equipLocations == "64":
+ image = "equipment/feet/boots.png|S:#3c3c3c,40332d,4d4d4d,5e4a3d,686868,705740,919191,a1825d,b6b6b6,b59767,dfdfdf,dbbf88"
+ typeStr = "equip-feet"
+ spriteStr = "equipment/feet/boots-male.xml|#40332d,5e4a3d,705740,a1825d,b59767,dbbf88";
+ elif equipLocations == "136":
+ image = "equipment/chest/cottonshirt.png|S:#3c3c3c,3e3c38,4d4d4d,514d47,686868,706662,919191,99917b,b6b6b6,c0b698,dfdfdf,e4dfca"
+ typeStr = "equip-torso"
+ spriteStr = "equipment/chest/cottonshirt-male.xml|#43413d,59544f,7a706c,8a8176,a69e88,d1c7a7,e0d5bf";
+ elif equipLocations == "256":
+ image = "equipment/head/bandana.png"
+ typeStr = "equip-head"
+ spriteStr = "equipment/head/bandana-male.xml";
+ elif equipLocations == "512":
+ # no sprites in evol
+ image = "equipment/chest/sailorshirt.png"
+ typeStr = "equip-torso"
+ spriteStr = "equipment/chest/shirt-male.xml|#131913,1b231d,233129,35433e,4e6059,6c8279;#72571e,836737,a5854d,b18f45";
+
+ name = strToXml(name);
+
+ if itemId not in ids:
+ ids.add(itemId)
+ data = data + tpl.format(itemId, name, 0,
+ statStr, image, typeStr, spriteStr)
+ if view != "0" and view not in ids:
+ ids.add(view)
+ data = data + tpl.format(view, name, 0,
+ statStr, image, typeStr, spriteStr)
+
+ saveFile(destDir + "items.xml", items.format(data))
diff --git a/hercules/code/servertoclient/luas.py b/hercules/code/servertoclient/luas.py
new file mode 100644
index 0000000..8b401b7
--- /dev/null
+++ b/hercules/code/servertoclient/luas.py
@@ -0,0 +1,51 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2015 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+comaSplit = re.compile(",")
+equalSplit = re.compile("=")
+
+def extractLuaArray(fileName, arrName):
+ with open(fileName, "r") as f:
+ for line in f:
+ if line.find(arrName) == 0:
+ line = line[line.find("{") + 1:]
+ line = line[:line.find("}")]
+ return line
+ return ""
+
+def convertJobName():
+ jobs = dict()
+ jobNameFile = "rodata/decompiled/jobname.lua"
+ line = extractLuaArray(jobNameFile, "JobNameTable")
+ arr = comaSplit.split(line)
+ for itemStr in arr:
+ parts = equalSplit.split(itemStr.strip())
+ if parts[0].find("[jobtbl.") == 0:
+ key = parts[0].strip()
+ key = key[8:-1].strip()
+ val = parts[1].strip()
+ val = val[1:-1].strip()
+ jobs[key] = val
+ return jobs
+
+def convertIdentity(jobs):
+ idents = dict()
+ npcIdentityFile = "rodata/decompiled/npcidentity.lua"
+ line = extractLuaArray(npcIdentityFile, "jobtbl = ")
+ arr = comaSplit.split(line)
+ for itemStr in arr:
+ parts = equalSplit.split(itemStr.strip())
+ key = parts[0].strip()
+ val = parts[1].strip()
+ if key in jobs:
+ idents[val] = jobs[key].lower()
+ return idents
+
+def convertLuas():
+ jobs = convertJobName()
+ idtofile = convertIdentity(jobs)
+ return idtofile
diff --git a/hercules/code/servertoclient/maps.py b/hercules/code/servertoclient/maps.py
new file mode 100644
index 0000000..0f1ca5b
--- /dev/null
+++ b/hercules/code/servertoclient/maps.py
@@ -0,0 +1,48 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import zlib
+
+from code.fileutils import readInt16, readInt32, makeDir, copyFile, readFile, readMapName, saveFile, readData
+from code.tileutils import getTileData, getTile
+
+def covertToTmx(f, mapsCount):
+ destDir = "clientdata/"
+ mapsDir = destDir + "maps/"
+ tilesetsDir = destDir + "graphics/tilesets/"
+ templatesDir = "templates/"
+ makeDir(mapsDir)
+ makeDir(tilesetsDir)
+ copyFile(templatesDir, tilesetsDir, "collision.png")
+ copyFile(templatesDir, tilesetsDir, "tileset.png")
+ tmx = readFile("templates/template.tmx")
+ for i in xrange(0, mapsCount):
+ name = readMapName(f)
+ print "converting map [{0:4}/{1:4}]: {2}".format(i, mapsCount + 1, name)
+ sx = readInt16(f)
+ sy = readInt16(f)
+ sz = readInt32(f)
+ mapData = readData(f, sz)
+ dc = zlib.decompressobj()
+ mapData = dc.decompress(mapData)
+ ground = ""
+ collision = ""
+ fringe = ""
+ for y in xrange(0, sy):
+ for x in xrange(0, sx):
+ tileData = getTileData(mapData, x, y, sx)
+ tile = getTile(tileData)
+ if x + 1 == sx and y + 1 == sy:
+ ground = ground + tile[0]
+ collision = collision + tile[1]
+ fringe = fringe + "0";
+ else:
+ ground = ground + tile[0] + ","
+ collision = collision + tile[1] + ","
+ fringe = fringe + "0,";
+ ground = ground + "\n"
+ collision = collision + "\n"
+ fringe = fringe + "\n"
+ saveFile(mapsDir + name + ".tmx", tmx.format(sx, sy, ground, collision, fringe))
diff --git a/hercules/code/servertoclient/mercenaries.py b/hercules/code/servertoclient/mercenaries.py
new file mode 100644
index 0000000..481f66c
--- /dev/null
+++ b/hercules/code/servertoclient/mercenaries.py
@@ -0,0 +1,31 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+from code.fileutils import makeDir, readFile, saveFile
+
+def convertMercenaries():
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ mercenariesDbFile = "serverdata/db/mercenary_db.txt"
+ fieldsSplit = re.compile(",")
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "mercenary.tpl")
+ mercenaries = readFile(templatesDir + "mercenaries.xml")
+ data = ""
+ mercenarySprite = "<sprite>monsters/croc.xml</sprite>";
+ with open(mercenariesDbFile, "r") as f:
+ for line in f:
+ if line == "" or line[0:2] == "//":
+ continue
+ rows = fieldsSplit.split(line)
+ if len(rows) < 9:
+ continue
+ data = data + tpl.format(
+ id = rows[0],
+ sprite = mercenarySprite,
+ name = rows[2])
+ saveFile(destDir + "mercenaries.xml", mercenaries.format(data))
diff --git a/hercules/code/servertoclient/monsters.py b/hercules/code/servertoclient/monsters.py
new file mode 100644
index 0000000..969795d
--- /dev/null
+++ b/hercules/code/servertoclient/monsters.py
@@ -0,0 +1,43 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+from code.fileutils import makeDir, readFile, saveFile
+from code.stringutils import strToXml, stripQuotes
+
+def convertMonsters(isNonFree = False, idtofile = None):
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ monstersDbFile = "serverdata/sql-files/mob_db_re.sql"
+ fieldsSplit = re.compile(",")
+ bracketsSplit = re.compile("[(]|[)]")
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "monster.tpl")
+ monsters = readFile(templatesDir + "monsters.xml")
+ data = ""
+
+ with open(monstersDbFile, "r") as f:
+ for line in f:
+ if len(line) < 10 or line[0:2] == "//" or line[0:12] != "REPLACE INTO":
+ continue
+ rows = bracketsSplit.split(line)
+ if len(rows) < 2:
+ continue
+ rows = fieldsSplit.split(rows[1])
+ if len(rows) < 5:
+ continue
+ monsterId = rows[0]
+ if isNonFree == True and monsterId in idtofile:
+ #convertSprite("rodata/data/sprite/ёуЅєЕН/", idtofile[monsterId])
+ monsterSprite = "<sprite>sprites/{0}.xml</sprite>".format(idtofile[monsterId])
+ else:
+ monsterSprite = """<sprite>monsters/blub.xml</sprite>
+ <sprite>accessories/blub-tentacle.xml|#3e4164,3a3968,544a82,64437a,7d6db4,a26392,8f99c4,d294ab,b3cdcd,e7b8b8,d9ecd1,f0e8c5</sprite>""";
+
+ name = strToXml(stripQuotes(rows[2]))
+ data = data + tpl.format(monsterId, name, monsterSprite)
+
+ saveFile(destDir + "monsters.xml", monsters.format(data))
diff --git a/hercules/code/servertoclient/npcs.py b/hercules/code/servertoclient/npcs.py
new file mode 100644
index 0000000..5e49ffd
--- /dev/null
+++ b/hercules/code/servertoclient/npcs.py
@@ -0,0 +1,29 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2015 Evol Online
+# Author: Andrei Karas (4144)
+
+from code.fileutils import makeDir, readFile, saveFile
+
+
+def getNpcIds(idtofile):
+ for key1 in idtofile:
+ key = int(key1)
+ if 45 <= key <= 125 or 400 < key < 1000 or 10001 <= key < 10100:
+ yield key1
+
+
+def convertNpcsNonFree(idtofile):
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "npc.tpl")
+ npcs = readFile(templatesDir + "npcs.xml")
+ data = ""
+
+ for key in getNpcIds(idtofile):
+ npcSprite = "<sprite>sprites/{0}.xml</sprite>".format(idtofile[key])
+ data = data + tpl.format(
+ id = key,
+ sprite = npcSprite)
+ saveFile(destDir + "npcs.xml", npcs.format(data))
diff --git a/hercules/code/servertoclient/pets.py b/hercules/code/servertoclient/pets.py
new file mode 100644
index 0000000..bc6deef
--- /dev/null
+++ b/hercules/code/servertoclient/pets.py
@@ -0,0 +1,31 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+from code.fileutils import makeDir, readFile, saveFile
+
+def convertPets():
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ petsDbFile = "serverdata/db/re/pet_db.txt"
+ fieldsSplit = re.compile(",")
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "pet.tpl")
+ pets = readFile(templatesDir + "pets.xml")
+ data = ""
+ petSprite = "<sprite>monsters/tortuga.xml</sprite>";
+ with open(petsDbFile, "r") as f:
+ for line in f:
+ if line == "" or line[0:2] == "//":
+ continue
+ rows = fieldsSplit.split(line)
+ if len(rows) < 9:
+ continue
+ data = data + tpl.format(
+ id = rows[0],
+ sprite = petSprite,
+ name = rows[2])
+ saveFile(destDir + "pets.xml", pets.format(data))
diff --git a/hercules/code/servertoclient/quests.py b/hercules/code/servertoclient/quests.py
new file mode 100644
index 0000000..df47fd5
--- /dev/null
+++ b/hercules/code/servertoclient/quests.py
@@ -0,0 +1,39 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+from code.fileutils import makeDir, readFile, saveFile
+from code.stringutils import strToXml, stripQuotes
+
+def convertQuests():
+ print "quests disabled for now"
+ return
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ questsDbFile = "serverdata/db/quest_db.txt"
+ fieldsSplit = re.compile(",")
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "quest.tpl")
+ quests = readFile(templatesDir + "quests.xml")
+ data = ""
+ with open(questsDbFile, "r") as f:
+ for line in f:
+ if line == "" or line[0:2] == "//":
+ continue
+ rows = fieldsSplit.split(line)
+ if len(rows) < 9:
+ continue
+ questId = rows[0]
+ text = rows[8]
+ if text[-1] == "\n":
+ text = text[:-1]
+ text = strToXml(stripQuotes(text))
+ name = text
+ if len(name) > 20:
+ name = name[:19]
+
+ data = data + tpl.format(questId, name, text + ": " + str(questId))
+ saveFile(destDir + "quests.xml", quests.format(data))
diff --git a/hercules/code/servertoclient/skills.py b/hercules/code/servertoclient/skills.py
new file mode 100644
index 0000000..6affb72
--- /dev/null
+++ b/hercules/code/servertoclient/skills.py
@@ -0,0 +1,33 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2014 Evol Online
+# Author: Andrei Karas (4144)
+
+import re
+
+from code.fileutils import makeDir, readFile, saveFile
+
+def convertSkillsToXml():
+ destDir = "clientdata/"
+ templatesDir = "templates/"
+ skillsDbFile = "serverdata/db/re/skill_db.txt"
+ fieldsSplit = re.compile(",")
+ makeDir(destDir)
+ tpl = readFile(templatesDir + "skill.tpl")
+ skills = readFile(templatesDir + "skills.xml")
+ data = ""
+ with open(skillsDbFile, "r") as f:
+ for line in f:
+ if line == "" or line[0:2] == "//":
+ continue
+ rows = fieldsSplit.split(line)
+ if len(rows) < 9:
+ continue
+ skillId = rows[0]
+ name = rows[15].strip()
+ description = rows[16].strip()
+ idx = description.find ("//")
+ if idx > 1:
+ description = description[:idx]
+ data = data + tpl.format(skillId, name, description)
+ saveFile(destDir + "skills.xml", skills.format(data))
diff --git a/hercules/code/servertoclient/sprites.py b/hercules/code/servertoclient/sprites.py
new file mode 100644
index 0000000..5dad9d1
--- /dev/null
+++ b/hercules/code/servertoclient/sprites.py
@@ -0,0 +1,467 @@
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2015 Evol Online
+# Author: Andrei Karas (4144)
+
+import array
+import os
+from PIL import Image
+
+from code.fileutils import readInt8, readInt16, readInt32, makeDir, readFile, saveFile, skipData, readData, findFileIn
+
+class ActClass:
+ pass
+
+class ActAnimationClass:
+ pass
+
+class ActSpriteClass:
+ pass
+
+class ActFrameClass:
+ pass
+
+class ActPivotClass:
+ pass
+
+class ActEventClass:
+ pass
+
+class SprClass:
+ pass
+
+class SprImageClass:
+ pass
+
+def readIndexedRLEImage(f, spr):
+ spr.nimages = spr.indexedSpritesCount
+ spr.images = dict()
+ for imageN in range(0, spr.indexedSpritesCount):
+ image = SprImageClass()
+ spr.images[imageN] = image
+ image.width = readInt16(f)
+ image.height = readInt16(f)
+ image.compressed = True
+ data = array.array('B', (0 for _ in xrange(image.width * image.height)))
+ image.data = data
+
+ compressSize = readInt16(f)
+ #uncompressedSize = image.width * image.height
+ #print "uncompressed size=" + str(uncompressedSize)
+ #print "compressed size=" + str(compressSize)
+
+ idx = 0
+ readCnt = 0
+ while readCnt < compressSize:
+ c = readInt8(f)
+ readCnt = readCnt + 1
+ data[idx] = c;
+ #print "{0:4}: {1}".format(idx, c)
+ idx = idx + 1
+ if c == 0:
+ cnt = readInt8(f)
+ readCnt = readCnt + 1
+ if cnt == 0:
+ data[idx] = cnt
+ #print "{0:4}: {1}".format(idx, cnt)
+ idx = idx + 1
+ else:
+ for j in range(1, cnt):
+ data[idx] = c
+ #print "{0:4} ({1} to {2}): {3}".format(idx, j, cnt - 1, c)
+ idx = idx + 1
+ #print "read bytes: " + str(readCnt)
+
+def readIndexedImage(f, spr):
+ pass
+
+def readRgbaImage(f, spr):
+ for imageN in range(0, spr.rgbaSpritesCount):
+ image = SprImageClass()
+ spr.images[imageN + spr.indexedSpritesCount] = image
+ image.width = readInt16(f)
+ image.height = readInt16(f)
+ data = array.array('I', (0 for _ in xrange(image.width * image.height)))
+ image.compressed = False
+ image.data = data
+ for idx in range(0, image.width * image.height):
+ data[idx] = readInt32(f)
+
+
+def readPalette(f, spr):
+ palette = array.array('I', (0 for _ in xrange(256)))
+ spr.palette = palette
+ for col in range(0, 256):
+ palette[col] = readInt32(f)
+
+def getSignedNumber(number, bitLength):
+ mask = (2 ** bitLength) - 1
+ if number & (1 << (bitLength - 1)):
+ return number | ~mask
+ else:
+ return number & mask
+
+def decodeSprite(spr):
+ palette = spr.palette
+ spr.maxwidth = 0
+ spr.maxheight = 0
+ alpha = False
+ for imageN in range(0, spr.indexedSpritesCount):
+ image = spr.images[imageN]
+ indexed = image.data
+ data = array.array('I', (0 for _ in xrange(image.width * image.height)))
+ for idx in range(0, image.width * image.height):
+ col = indexed[idx]
+ if col == 0:
+ data[idx] = 0
+ else:
+ if palette[col] > 0x00ffffff:
+ data[idx] = palette[col]
+ alpha = True
+ else:
+ data[idx] = palette[col] + 0xff000000
+ image.data = data
+ if image.width > spr.maxwidth:
+ spr.maxwidth = image.width
+ if image.height > spr.maxheight:
+ spr.maxheight = image.height
+
+ # for debug
+# png = Image.new('RGBA', (image.width, image.height))
+# png.putdata(image.data)
+# png.save("test{0}.png".format(imageN))
+
+ if alpha:
+ print "detected alpha"
+
+ for imageN in range(0, spr.rgbaSpritesCount):
+ image = spr.images[imageN + spr.indexedSpritesCount]
+ if image.width > spr.maxwidth:
+ spr.maxwidth = image.width
+ if image.height > spr.maxheight:
+ spr.maxheight = image.height
+
+
+
+def saveSpriteImage(act, spr, spriteDir, spriteName):
+# for imageN in range(0, spr.rgbaSpritesCount):
+# image = spr.images[imageN + spr.indexedSpritesCount]
+# print "{0} x {1}".format(image.width, image.height)
+# png = Image.new('RGBA', (image.width, image.height))
+# png.putdata(image.data)
+# png.save("test{0}.png".format(imageN + spr.indexedSpritesCount))
+
+# numTiles = spr.indexedSpritesCount + spr.rgbaSpritesCount
+
+ counted = 0
+ for animN in range(0, act.nanimations):
+ anim = act.animations[animN]
+ for spriteN in range(0, anim.nsprites):
+ sprite = anim.sprites[spriteN]
+# key = []
+# for frameN in range(0, sprite.nframes):
+# frame = sprite.frames[frameN]
+# idf = frame.frameIndex
+# if frame.mirror > 0:
+# idf = - idf
+# key.append(idf)
+ counted = counted + 1
+
+ numTiles = counted
+ #print "max: {0}x{1}".format(spr.maxwidth, spr.maxheight)
+
+ # in row
+ rowTiles = int(2048 / spr.maxwidth)
+ colTiles = int(numTiles / rowTiles)
+ if colTiles * rowTiles < numTiles:
+ colTiles = colTiles + 1
+ tilesetWidth = 2048
+ tilesetHeight = colTiles * spr.maxheight
+# print "num {0} row {1}, col {2}".format(numTiles, rowTiles, colTiles)
+# print "size {0}x{1}".format(2048, colTiles * spr.maxheight)
+
+# tileset = array.array('I', (0 for _ in xrange(tilesetWidth * tilesetHeight)))
+ tileset = Image.new('RGBA', (tilesetWidth, tilesetHeight))
+# png.putdata(tileset)
+ #draw = ImageDraw.Draw(png)
+
+ x = 0
+ y = 0
+
+ frameToIdx = dict()
+
+ tile = 0
+ for animN in range(0, act.nanimations):
+ anim = act.animations[animN]
+ for spriteN in range(0, anim.nsprites):
+ sprite = anim.sprites[spriteN]
+ frameToIdx[str(animN) + "_" + str(spriteN)] = tile
+ for frameN in range(0, sprite.nframes):
+ frame = sprite.frames[frameN]
+ frm = frame.frameIndex
+ if frame.mirror > 0:
+ frm = - frm
+
+ if frm in frameToIdx:
+ continue
+
+ if frame.frameIndex not in spr.images:
+ print "wrong frame index: {0}".format(frame.frameIndex)
+ continue
+ image = spr.images[frame.frameIndex]
+ png = Image.new('RGBA', (image.width, image.height))
+ png.putdata(image.data)
+ if frame.mirror > 0:
+ png = png.transpose(Image.FLIP_LEFT_RIGHT)
+ offsetX = (spr.maxwidth - image.width) / 2
+ offsetY = spr.maxheight - image.height
+# offsetX = (spr.maxwidth - image.width) / 2 + getSignedNumber(frame.offsetX, 32)
+# offsetY = spr.maxheight - image.height + getSignedNumber(frame.offsetY, 32)
+ tileset.paste(png, (x + offsetX, y + offsetY))
+ tile = tile + 1
+ x = x + spr.maxwidth
+ if x + spr.maxwidth > 2048:
+ x = 0
+ y = y + spr.maxheight
+
+# for imageN in range(0, spr.rgbaSpritesCount + spr.indexedSpritesCount):
+# image = spr.images[imageN]
+# png = Image.new('RGBA', (image.width, image.height))
+# png.putdata(image.data)
+# tileset.paste(png, (x, y))
+# x = x + spr.maxwidth
+# if x + spr.maxwidth > 2048:
+# x = 0
+# y = y + spr.maxheight
+
+ spr.frameToIdx = frameToIdx
+ spr.tilesetWidth = tilesetWidth
+ spr.tilesetHeight = tilesetHeight
+ makeDir(spriteDir)
+ tileset.save(spriteDir + spriteName + ".png")
+
+def extractSpriteAnimData(act, spr, actIndex, direction):
+# delay = anim.delay
+ delay = 100
+ data = " <animation direction=\"" + direction + "\">\n"
+ if actIndex not in act.animations:
+ data = data + " <frame index=\"{0}\" delay=\"{1}\" offsetX=\"{2}\" offsetY=\"{3}\"/>\n".format(
+ 0, delay, 0, 0)
+ data = data + " </animation>\n"
+ return data
+
+ anim = act.animations[actIndex]
+ for spriteN in range(0, anim.nsprites):
+ #sprite = anim.sprites[spriteN]
+ #for frameN in range(0, sprite.nframes):
+ #frame = sprite.frames[frameN]
+ #frm = frame.frameIndex
+ #if frame.mirror > 0:
+ # frm = -frm
+ #if frm not in spr.frameToIdx:
+ # continue
+
+ idx = spr.frameToIdx[str(actIndex) + "_" + str(spriteN)]
+ offsetX = 0
+ offsetY = 0
+# offsetX = frame.offsetX
+# offsetY = frame.offsetY
+# if offsetX > 4294900000:
+# offsetX = - (4294967296 - offsetX)
+# if offsetY > 4294000000:
+# offsetY = -(4294967296 - offsetY)
+
+ data = data + " <frame index=\"{0}\" delay=\"{1}\" offsetX=\"{2}\" offsetY=\"{3}\"/>\n".format(
+ idx, delay, offsetX, offsetY)
+
+ data = data + " </animation>\n"
+ return data
+
+def extractSpriteDataAll(act, spr, actIndex, name):
+ data = extractSpriteAnimData(act, spr, actIndex, "down")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 1, "downleft")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 2, "left")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 3, "upleft")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 4, "up")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 5, "upright")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 6, "right")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 6, "downright")
+ return data
+
+def saveSpriteXml(act, spr, spriteDir, spriteName):
+ templatesDir = "templates/"
+ dstFile = spriteDir + spriteName + ".xml"
+ tpl = readFile(templatesDir + "sprite.xml")
+ # 0, 8, 16, 24, 32, 40, 48
+ # 0 - walk or attack or ?
+ # 8 - walk
+ # 16 - attack
+ # 24 - dead
+ # 32 - dead2 ?
+ # no more
+ standData = extractSpriteDataAll(act, spr, 0, "stand")
+ walkData = extractSpriteDataAll(act, spr, 8, "walk")
+ attackData = extractSpriteDataAll(act, spr, 16, "attack")
+ deadData = extractSpriteDataAll(act, spr, 32, "dead")
+
+ data = tpl.format(
+ src = "graphics/sprites/sprites/" + spriteName + ".png",
+ width = spr.maxwidth,
+ height = spr.maxheight,
+ stand = standData,
+ walk = walkData,
+ attack = attackData,
+ dead = deadData
+ )
+ saveFile(dstFile, data)
+
+
+def readAct(actFile):
+ act = ActClass()
+ with open(actFile, "r") as f:
+ act.header = readInt16(f)
+ if act.header != 17217:
+ #print "Wrong header in file {0}".format(actFile)
+ return None
+ act.minorVersion = readInt8(f)
+ act.majorVersion = readInt8(f)
+ act.nanimations = readInt16(f)
+ print "{0}, {1}.{2}, {3}".format(actFile, act.majorVersion, act.minorVersion, act.nanimations)
+ #print " animations: " + str(act.nanimations)
+ act.animations = dict()
+ skipData(f, 10)
+ for animN in range(0, act.nanimations):
+ anim = ActAnimationClass()
+ anim.delay = 30
+ act.animations[animN] = anim
+ anim.nsprites = readInt32(f)
+ #print " sprites: " + str(anim.nsprites)
+ anim.sprites = dict()
+ for spriteN in range(0, anim.nsprites):
+ sprite = ActSpriteClass()
+ anim.sprites[spriteN] = sprite
+ sprite.left1 = readInt32(f)
+ sprite.top1 = readInt32(f)
+ sprite.right1 = readInt32(f)
+ sprite.buttom1 = readInt32(f)
+ sprite.left2 = readInt32(f)
+ sprite.top2 = readInt32(f)
+ sprite.right2 = readInt32(f)
+ sprite.buttom2 = readInt32(f)
+ sprite.nframes = readInt32(f)
+ #print "sprite {0}, frames: {1}".format(spriteN, sprite.nframes)
+ sprite.frames = dict()
+ for frameN in range(0, sprite.nframes):
+ frame = ActFrameClass()
+ sprite.frames[frameN] = frame
+ frame.offsetX = readInt32(f)
+ frame.offsetY = readInt32(f)
+ frame.frameIndex = readInt32(f)
+ #print " index: " + str(frame.frameIndex)
+ frame.mirror = readInt32(f)
+ if act.majorVersion >= 2:
+ frame.color = readInt32(f)
+ frame.scaleX = readInt32(f)
+ if act.majorVersion > 2 or (act.majorVersion == 2 and act.minorVersion >= 4):
+ frame.scaleY = readInt32(f)
+ else:
+ frame.scaleY = frame.scaleX
+ frame.angle = readInt32(f)
+ frame.spriteType = readInt32(f)
+ if act.majorVersion > 2 or (act.majorVersion == 2 and act.minorVersion >= 5):
+ frame.width = readInt32(f)
+ frame.height = readInt32(f)
+ #print "{0} x {1}".format(frame.width, frame.height)
+ if act.majorVersion >= 2:
+ sprite.eventIndex = readInt32(f)
+ if act.majorVersion > 2 or (act.majorVersion == 2 and act.minorVersion >= 3):
+ sprite.npivots = readInt32(f)
+ sprite.pivots = dict()
+ #if sprite.npivots > 0:
+ #print " pivotes: " + str(sprite.npivots)
+ for pivotN in range(0, sprite.npivots):
+ pivot = ActPivotClass()
+ sprite.pivots[pivotN] = pivot
+ pivot.unknown = readInt32(f)
+ pivot.centerX = readInt32(f)
+ pivot.centerY = readInt32(f)
+ pivot.nAttribute = readInt32(f)
+ if act.majorVersion > 2 or (act.majorVersion == 2 and act.minorVersion >= 1):
+ act.nevents = readInt32(f)
+ act.events = dict()
+ for eventN in range(0, act.nevents):
+ event = ActEventClass()
+ act.events[eventN] = event;
+ event.name = readData(f, 40)
+ if act.majorVersion > 2 or (act.majorVersion == 2 and act.minorVersion >= 2):
+ for animN in range(0, act.nanimations):
+ anim = act.animations[animN]
+ anim.delay = readInt32(f)
+ return act
+
+def readSpr(sprFile):
+ spr = SprClass()
+ with open(sprFile, "r") as f:
+ spr.header1 = readInt8(f)
+ spr.header2 = readInt8(f)
+ if spr.header1 != 0x53 or spr.header2 != 0x50:
+ return None
+ spr.minorVersion = readInt8(f)
+ spr.majorVersion = readInt8(f)
+ spr.indexedSpritesCount = readInt16(f)
+ if spr.majorVersion > 1 or (spr.majorVersion == 1 and spr.minorVersion >= 1):
+ spr.rgbaSpritesCount = readInt16(f)
+ else:
+ spr.rgbaSpritesCount = 0
+ print "{0}, {1}.{2}, {3}, {4}".format(sprFile, spr.majorVersion, spr.minorVersion, spr.indexedSpritesCount, spr.rgbaSpritesCount)
+ spr.frames = spr.indexedSpritesCount + spr.rgbaSpritesCount
+
+ if spr.majorVersion > 2 or (spr.majorVersion == 2 and spr.minorVersion >= 1):
+ readIndexedRLEImage(f, spr)
+ else:
+ readIndexedImage(f, spr)
+ readRgbaImage(f, spr)
+
+ if spr.majorVersion > 1 or (spr.majorVersion == 1 and spr.minorVersion >= 1):
+ readPalette(f, spr)
+
+ return spr
+
+def convertSprite(spritePath, spriteName):
+ actFile = "{0}.act".format(spritePath + spriteName)
+ sprFile = "{0}.spr".format(spritePath + spriteName)
+ if os.path.exists(actFile) == False or os.path.exists(sprFile) == False:
+ return None
+ act = readAct(actFile)
+ spr = readSpr(sprFile)
+ decodeSprite(spr)
+ saveSpriteImage(act, spr, "clientdata/graphics/sprites/sprites/", spriteName)
+ saveSpriteXml(act, spr, "clientdata/graphics/sprites/sprites/", spriteName)
+# if actFile.find("wolf") > 0:
+# exit(0)
+# exit(0)
+
+def findSpritePath(spriteName):
+ testName = spriteName + ".act"
+ testName2 = spriteName.upper() + ".act"
+ path = findFileIn((testName, testName2),
+ ("rodata/data/sprite/ёуЅєЕН/",
+ "rodata/data/sprite/npc/",
+ "rodata/data/sprite/homun/"))
+ return path
+
+def convertSpritesNonFree(idtofile):
+ processed = []
+ for spriteid in idtofile:
+ spriteName = idtofile[spriteid]
+ if spriteName in processed:
+ print "skipping " + spriteName
+ continue
+
+ path = findSpritePath(spriteName)
+ if path is None:
+ print "not found " + spriteName
+ continue
+ print spriteName
+ convertSprite(path, spriteName)
+ processed.append(spriteName)