summaryrefslogtreecommitdiff
path: root/hercules/code/servertoclient/sprites.py
diff options
context:
space:
mode:
Diffstat (limited to 'hercules/code/servertoclient/sprites.py')
-rw-r--r--hercules/code/servertoclient/sprites.py315
1 files changed, 304 insertions, 11 deletions
diff --git a/hercules/code/servertoclient/sprites.py b/hercules/code/servertoclient/sprites.py
index 1a04745..7e03b58 100644
--- a/hercules/code/servertoclient/sprites.py
+++ b/hercules/code/servertoclient/sprites.py
@@ -4,6 +4,9 @@
# Author: Andrei Karas (4144)
import os
+from PIL import Image
+from PIL import ImageDraw
+from sets import Set
from code.fileutils import *
from code.stringutils import *
@@ -29,14 +32,293 @@ class ActEventClass:
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):
- pass
+ 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, spriteName):
+ monstersDir = "clientdata/graphics/sprites/monsters/"
+# 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(monstersDir)
+ tileset.save(monstersDir + 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, "leftdown")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 2, "left")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 3, "leftup")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 4, "up")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 5, "rightup")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 6, "right")
+ data = data + extractSpriteAnimData(act, spr, actIndex + 6, "rightdown")
+ return data
+
+def saveSpriteXml(act, spr, spriteName):
+ monstersDir = "clientdata/graphics/sprites/monsters/"
+ templatesDir = "templates/"
+ dstFile = monstersDir + 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/monsters/" + spriteName + ".png",
+ width = spr.maxwidth,
+ height = spr.maxheight,
+ stand = standData,
+ walk = walkData,
+ attack = attackData,
+ dead = deadData
+ )
+ saveFile(dstFile, data)
+
def readAct(actFile):
act = ActClass()
@@ -47,13 +329,14 @@ def readAct(actFile):
return None
act.minorVersion = readInt8(f)
act.majorVersion = readInt8(f)
- #print "file: {0}, version: {1}.{2}".format(actFile, act.majorVersion, act.minorVersion)
act.nanimations = readInt16(f)
+ print "{0}, {1}.{2}, {1}".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)
@@ -70,8 +353,8 @@ def readAct(actFile):
sprite.right2 = readInt32(f)
sprite.buttom2 = readInt32(f)
sprite.nframes = readInt32(f)
+ #print "sprite {0}, frames: {1}".format(spriteN, sprite.nframes)
sprite.frames = dict()
- #print " frames: " + str(sprite.nframes)
for frameN in range(0, sprite.nframes):
frame = ActFrameClass()
sprite.frames[frameN] = frame
@@ -92,8 +375,7 @@ def readAct(actFile):
if act.majorVersion > 2 or (act.majorVersion == 2 and act.minorVersion >= 5):
frame.width = readInt32(f)
frame.height = readInt32(f)
- #print " width: " + str(frame.width)
- #print " height: " + str(frame.height)
+ #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):
@@ -119,6 +401,7 @@ def readAct(actFile):
for animN in range(0, act.nanimations):
anim = act.animations[animN]
anim.delay = readInt32(f)
+ return act
def readSpr(sprFile):
spr = SprClass()
@@ -143,11 +426,21 @@ def readSpr(sprFile):
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(spriteName):
- actFile = "{0}.act".format(spriteName)
- sprFile = "{0}.spr".format(spriteName)
+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
- #readAct(actFile)
- readSpr(sprFile)
+ act = readAct(actFile)
+ spr = readSpr(sprFile)
+ decodeSprite(spr)
+ saveSpriteImage(act, spr, spriteName)
+ saveSpriteXml(act, spr, spriteName)
+# if actFile.find("wolf") > 0:
+# exit(0)
+# exit(0)