Loading

Paste #psq5oyyug

  1. # https://github.com/alexandergitter/theme-hospital-spec/blob/master/format-specification.md
  2.  
  3. class Reader:
  4.     def __init__(self, fname):
  5.         self.load(fname)
  6.  
  7.     def load(self, fname):
  8.         handle = open(fname, 'rb')
  9.         self.data = handle.read()
  10.         self.offset = 0
  11.         handle.close()
  12.  
  13.     def reset(self):
  14.         self.offset = 0
  15.  
  16.     def size(self):
  17.         return len(self.data)
  18.  
  19.     def get(self, index):
  20.         return self.data[index]
  21.  
  22.     def byte(self):
  23.         assert self.offset < self.size()
  24.         b = self.data[self.offset]
  25.         self.offset = self.offset + 1
  26.         return b
  27.  
  28.     def word(self):
  29.         b = self.byte()
  30.         c = self.byte()
  31.         return b | (c << 8)
  32.  
  33.     def long(self):
  34.         b = self.word()
  35.         c = self.word()
  36.         return b | (c << 16)
  37.  
  38. class Palette:
  39.     def __init__(self):
  40.         self.palette = None
  41.  
  42.     def load(self, reader):
  43.         reader.reset()
  44.         assert reader.size() == 3 * 256
  45.         self.palette = []
  46.         for i in range(256):
  47.             r = reader.byte()
  48.             g = reader.byte()
  49.             b = reader.byte()
  50.             self.palette.append((r, g, b))
  51.  
  52. def make_palette(fname):
  53.     reader = Reader(fname)
  54.     p = Palette()
  55.     p.load(reader)
  56.     return p
  57.  
  58. class Frame:
  59.     """
  60.    Meta information of a single frame.
  61.  
  62.    frame_offset: Offset of the frame in the image file.
  63.    width: Width of the image
  64.    height: Height of the image
  65.    soundindex: If not 0, index into the filetable of the sounds data file
  66.    start_animation: Whether this frame is the start of an animation
  67.    next_frame: Index of the next frame in the L{Frames} list.
  68.    """
  69.     def __init__(self, listindex, width, height, soundindex, flags, nextindex):
  70.         self.frame_offset = listindex * 2
  71.         self.width = width
  72.         self.height = height
  73.         self.soundindex = soundindex
  74.         self.start_animation = (flags & 1) != 0
  75.         self.next_frame = nextindex
  76.  
  77. class Frames:
  78.     """
  79.    All meta information of fromes in a file.
  80.    """
  81.     def __init__(self):
  82.         self.frames = []
  83.  
  84.     def load(self, reader):
  85.         reader.reset()
  86.  
  87.         length = reader.size()
  88.         assert length % 10 == 0
  89.  
  90.         self.frames = []
  91.         while length > 0:
  92.             lind = reader.long()
  93.             w = reader.byte()
  94.             h = reader.byte()
  95.             sindex = reader.byte()
  96.             flags = reader.byte()
  97.             nextframe = reader.word()
  98.             self.frames.append(Frame(lind, w, h, sindex, flags, nextframe))
  99.             length = length - 10
  100.  
  101. class FrameList:
  102.     def __init__(self):
  103.         self.list = []
  104.  
  105.     def load(self, reader):
  106.         reader.reset()
  107.  
  108.         assert reader.size() % 2 == 0
  109.         self.list = []
  110.         for i in range(reader.size() // 2):
  111.             w = reader.word()
  112.             if w == 0xffff:
  113.                 self.list.append(None)
  114.             else:
  115.                 self.list.append(w) # Position in the sprite elements.
  116.  
  117. class SpriteElement:
  118.     """
  119.    sprite_pos: Absolute position in the sprite table.
  120.    offset_x: Horizontal offset of the image.
  121.    offset_y: Vertical offset of the image.
  122.    layer_class: Layer class.
  123.    flags: Render flags.
  124.    layerid: Layer of this sprite.
  125.    """
  126.     def __init__(self, sprite_pos, offset_x, offset_y, layer_class, flags, layerid):
  127.         self.sprite_pos = sprite_pos
  128.         self.offset_x = offset_x
  129.         self.offset_y = offset_y
  130.         self.layer_class = layer_class
  131.         self.flags = flags
  132.         self.layerid = layerid
  133.  
  134.     def flip_vert(self):
  135.         """Whether to flip the image vertically on rendering"""
  136.         return (self.flags & 1) != 0
  137.  
  138.     def flip_hor(self):
  139.         """Whether to flip the image horizontally on rendering"""
  140.         return (self.flags & 2) != 0
  141.  
  142.     def alpha50(self):
  143.         """Whether to draw the inage with 50% alpha."""
  144.         return (self.flags & 4) != 0
  145.  
  146.     def alpha75(self):
  147.         """Whether to draw the inage with 75% alpha."""
  148.         return (self.flags & 8) != 0
  149.  
  150. class SpriteElements:
  151.     def __init__(self):
  152.         self.elements = []
  153.  
  154.     # XXX Finish me!
  155.  
  156. class SpriteTableElement:
  157.     def __init__(self, offset, width, height):
  158.         self.offset = offset
  159.         self.width = width
  160.         self.height = height
  161.  
  162.     def __str__(self):
  163.         return "offset={}, width={}, height={}".format(self.offset, self.width, self.height)
  164.  
  165. class SpriteTable:
  166.     def __init__(self):
  167.         self.sprites = []
  168.  
  169.     def load(self, reader):
  170.         reader.reset()
  171.  
  172.         length = reader.size()
  173.         print(length)
  174.         assert length % 6 == 0
  175.  
  176.         self.sprites = []
  177.         while length > 0:
  178.             offset = reader.long()
  179.             width = reader.byte()
  180.             height = reader.byte()
  181.             length = length - 6
  182.  
  183.             self.sprites.append(SpriteTableElement(offset, width, height))
  184.  
  185. def MakeSpriteTable(fname):
  186.     reader = Reader(fname)
  187.     sprt = SpriteTable()
  188.     sprt.load(reader)
  189.     return sprt
  190.  
  191. #data = load('CD/HOSP/DATA/VFRA-1.ANI')
  192. #Looks like Frames
  193.  
  194. pal = make_palette('MPALETTE.DAT.decoded')
  195. dat = Reader('VSPR-0.DAT.decoded')
  196.  
  197. sprt = MakeSpriteTable("VSPR-0.TAB.decoded")
  198. print("Number of sprites: {}".format(len(sprt.sprites)))
  199. #print("\n".join(str(s) for s in sprt.sprites))
  200.  
  201.  
  202. from PIL import Image
  203.  
  204. # Raw graphics
  205. def raw_graphics(spr, pal, reader):
  206.     print(spr)
  207.     im = Image.new("RGBA", (spr.width, spr.height), (0, 0, 0, 0))
  208.  
  209.     offset = spr.offset
  210.     for y in range(spr.height):
  211.         for x in range(spr.width):
  212.             v = reader.get(offset)
  213.             col = pal.palette[v]
  214.             col = (col[0], col[1], col[2], 255)
  215.             offset = offset + 1
  216.  
  217.             im.putpixel((x, y), col)
  218.     return im
  219.  
  220. def extra_chunk_graphics(spr, pal, reader):
  221.     if spr.width == 0 or spr.height == 0:
  222.         return None
  223.  
  224.     print(spr)
  225.     im = Image.new("RGBA", (spr.width, spr.height), (200, 0, 200, 255))
  226.  
  227.     offset = spr.offset
  228.     x, y = 0, 0
  229.     while y < spr.height:
  230.         v = reader.get(offset)
  231.         offset = offset + 1
  232.         if v == 0: # End of the row.
  233.             x, y = 0, y+1
  234.             continue
  235.  
  236.         if v <= 63: # v opaque pixels
  237.             while v > 0:
  238.                 w = reader.get(offset)
  239.                 offset = offset + 1
  240.  
  241.                 col = pal.palette[w]
  242.                 col = (col[0], col[1], col[2], 255)
  243.                 im.putpixel((x, y), col)
  244.                 x = x + 1
  245.                 if x >= spr.width:
  246.                     x, y = 0, y+1
  247.                     if y >= spr.height:
  248.                         break;
  249.  
  250.                 v = v - 1
  251.             continue
  252.  
  253.         if v <= 127: # (v-60) times the same pixel
  254.             v = v - 60
  255.             w = reader.get(offset)
  256.             offset = offset + 1
  257.             col = pal.palette[w]
  258.             col = (col[0], col[1], col[2], 255)
  259.             while v > 0:
  260.                 im.putpixel((x, y), col)
  261.                 x = x + 1
  262.                 if x >= spr.width:
  263.                     x, y = 0, y+1
  264.                     if y >= spr.height:
  265.                         break;
  266.  
  267.                 v = v - 1
  268.             continue
  269.  
  270.         if v < 192: # (v-128) transparent pixels
  271.             v = v - 128
  272.             while v > 0:
  273.                 x = x + 1
  274.                 if x >= spr.width:
  275.                     x, y = 0, y+1
  276.                     if y >= spr.height:
  277.                         break;
  278.                 v = v - 1
  279.             continue
  280.  
  281.         if v < 255: # (v - 124) times the same pixel
  282.             v = v - 124
  283.             w = reader.get(offset)
  284.             offset = offset + 1
  285.             col = pal.palette[w]
  286.             col = (col[0], col[1], col[2], 255)
  287.             while v > 0:
  288.                 im.putpixel((x, y), col)
  289.                 x = x + 1
  290.                 if x >= spr.width:
  291.                     x, y = 0, y+1
  292.                     if y >= spr.height:
  293.                         break;
  294.  
  295.                 v = v - 1
  296.             continue
  297.  
  298.         assert v == 255
  299.         V = reader.get(offset)
  300.         w = reader.get(offset)
  301.         col = pal.palette[w]
  302.         col = (col[0], col[1], col[2], 255)
  303.         while v > 0:
  304.             im.putpixel((x, y), col)
  305.             x = x + 1
  306.             if x >= spr.width:
  307.                 x, y = 0, y+1
  308.                 if y >= spr.height:
  309.                     break;
  310.  
  311.             v = v - 1
  312.  
  313.     return im
  314.  
  315.  
  316. for sprite in [5, 21, 345]:
  317.     #im = raw_graphics(sprt.sprites[sprite], pal, dat)
  318.     im = extra_chunk_graphics(sprt.sprites[sprite], pal, dat)
  319.     im.save('sprite_{}.png'.format(sprite))

Comments