diff options
Diffstat (limited to 'hercules/code/servertoclient')
-rw-r--r-- | hercules/code/servertoclient/__init__.py | 0 | ||||
-rw-r--r-- | hercules/code/servertoclient/groups.py | 185 | ||||
-rw-r--r-- | hercules/code/servertoclient/homunculuses.py | 31 | ||||
-rw-r--r-- | hercules/code/servertoclient/items.py | 138 | ||||
-rw-r--r-- | hercules/code/servertoclient/luas.py | 51 | ||||
-rw-r--r-- | hercules/code/servertoclient/maps.py | 48 | ||||
-rw-r--r-- | hercules/code/servertoclient/mercenaries.py | 31 | ||||
-rw-r--r-- | hercules/code/servertoclient/monsters.py | 43 | ||||
-rw-r--r-- | hercules/code/servertoclient/npcs.py | 29 | ||||
-rw-r--r-- | hercules/code/servertoclient/pets.py | 31 | ||||
-rw-r--r-- | hercules/code/servertoclient/quests.py | 39 | ||||
-rw-r--r-- | hercules/code/servertoclient/skills.py | 33 | ||||
-rw-r--r-- | hercules/code/servertoclient/sprites.py | 467 |
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) |