diff options
Diffstat (limited to 'hercules/code/servertoclient/sprites.py')
-rw-r--r-- | hercules/code/servertoclient/sprites.py | 467 |
1 files changed, 467 insertions, 0 deletions
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) |