def test_animation_mask1(self):
     # 2 frames, transparency on frame 2
     iw_args = {'options': self.alpha_option}
     frame1 = Frame([[Udg(49, (64,) * 8)]])
     frame2 = Frame([[Udg(184, (240,) * 8, (243,) * 8)]], mask=1)
     frames = [frame1, frame2]
     self._test_animated_image(frames, iw_args)
 def test_animation(self):
     # 3 frames, 2 colours, 16x8
     frame1 = Frame([[Udg(6, (128,) * 8), Udg(6, (0,) * 8)]], delay=20)
     frame2 = Frame([[Udg(6, (64,) * 8), Udg(6, (1,) * 8)]], delay=100)
     frame3 = Frame([[Udg(6, (32,) * 8), Udg(6, (2,) * 8)]], delay=150)
     frames = [frame1, frame2, frame3]
     self._test_animated_image(frames)
 def test_animation_with_frames_of_different_sizes(self):
     # First frame 16x8, second frame 8x16, third frame 8x8
     frame1 = Frame([[Udg(1, (0,) * 8)] * 2])
     frame2 = Frame([[Udg(1, (0,) * 8)]] * 2)
     frame3 = Frame([[Udg(1, (0,) * 8)]])
     frames = [frame1, frame2, frame3]
     self._test_animated_image(frames)
    def _animate_conveyor(self, udgs, direction, x, y, length, scale):
        mask = 0
        delay = 10
        frame1 = Frame(udgs, scale, mask, delay=delay)
        frames = [frame1]

        if y < 0 or y >= len(udgs) or x + length < 0 or x >= len(udgs[0]):
            return frames
        min_x = max(x, 0)
        max_x = min(x + length, len(udgs[0]))
        length_t = max_x - min_x

        base_udg = prev_udg = udgs[y][min_x]
        while True:
            next_udg = prev_udg.copy()
            data = next_udg.data
            if direction:
                data[0] = (data[0] >> 2) + (data[0] & 3) * 64
                data[2] = ((data[2] << 2) & 255) + (data[2] >> 6)
            else:
                data[0] = ((data[0] << 2) & 255) + (data[0] >> 6)
                data[2] = (data[2] >> 2) + (data[2] & 3) * 64
            if next_udg.data == base_udg.data:
                break
            next_udgs = [row[:] for row in udgs]
            next_udgs[y][min_x:max_x] = [next_udg] * length_t
            frames.append(Frame(next_udgs, scale, mask, delay=delay))
            prev_udg = next_udg
        return frames
 def test_animation_with_alternative_transparent_colour_on_first_frame_only(self):
     # White (PAPER) as transparent colour on first frame
     iw_args = {'options': self.alpha_option}
     frame1 = Frame([[Udg(56, (15,) * 8)]], tindex=8)
     frame2 = Frame([[Udg(1, (15,) * 8)]])
     frames = [frame1, frame2]
     self._test_animated_image(frames, iw_args)
 def test_animation_with_alternative_transparent_colour_on_second_frame_only(self):
     # Yellow (PAPER) as transparent colour on second frame
     iw_args = {'options': self.alpha_option}
     frame1 = Frame([[Udg(56, (15,) * 8)]], tindex=7)
     frame2 = Frame([[Udg(48, (15,) * 8)]])
     frames = [frame1, frame2]
     self._test_animated_image(frames, iw_args)
 def test_animation_with_alternative_transparent_colour_overridden_by_mask(self):
     # White (PAPER) as transparent colour on first frame, overridden by
     # mask on second frame
     iw_args = {'options': self.alpha_option}
     frame1 = Frame([[Udg(56, (15,) * 8)]], tindex=8)
     frame2 = Frame([[Udg(56, (15,) * 8, (207,) * 8)]], mask=1)
     frames = [frame1, frame2]
     self._test_animated_image(frames, iw_args)
 def cavern(self,
            cwd,
            address,
            scale=2,
            fname=None,
            x=0,
            y=0,
            w=32,
            h=17,
            guardians=1,
            animate=0):
     if fname is None:
         fname = self.cavern_names[address].lower().replace(' ', '_')
     cavern_udgs = self._get_cavern_udgs(address, guardians)
     img_udgs = [
         cavern_udgs[i][x:x + w] for i in range(y, y + min(h, 17 - y))
     ]
     if animate:
         direction = self.snapshot[address + 623]
         sb_addr = self.snapshot[address +
                                 624] + 256 * self.snapshot[address + 625]
         conveyor_x = sb_addr % 32 - x
         conveyor_y = 8 * (
             (sb_addr - 28672) // 2048) + (sb_addr % 256) // 32 - y
         length = self.snapshot[address + 626]
         frames = self._animate_conveyor(img_udgs, direction, conveyor_x,
                                         conveyor_y, length, scale)
     else:
         frames = [Frame(img_udgs, scale)]
     return self.handle_image(frames,
                              fname,
                              cwd,
                              path_id='ScreenshotImagePath')
Exemple #9
0
def run(snafile, imgfname, options):
    snapshot = get_snapshot(snafile)
    skool = BackToSkool(snapshot)
    width = 192
    eric = 210
    for address in options.mutable:
        skool.alter_skool_udgs(address)
    x = y = 0
    height = 21
    skool.hide_chars()

    if options.blackboard:
        bb = BLACKBOARDS[options.blackboard]
        width, height, x, y = bb['geometry']
        eric_x, eric_y = bb['location']
        skool.place_char(eric, eric_x, eric_y, 0)
    elif options.geometry:
        wh, xy = options.geometry.split('+', 1)
        width, height = [int(n) for n in wh.split('x')]
        x, y = [int(n) for n in xy.split('+')]

    for spec in options.text:
        board_id, sep, text = spec.partition(':')
        if sep:
            bb = BLACKBOARDS[board_id]
            skool.write(bb['tiles'], text)

    for spec in options.place_char:
        values = []
        for n in spec.split(','):
            try:
                values.append(int(n))
            except ValueError:
                values.append(None)
        skool.place_char(*values[:4])

    for spec in options.pokes:
        addr, val = spec.split(',', 1)
        step = 1
        if '-' in addr:
            addr1, addr2 = addr.split('-', 1)
            addr1 = int(addr1)
            if '-' in addr2:
                addr2, step = [int(i) for i in addr2.split('-', 1)]
            else:
                addr2 = int(addr2)
        else:
            addr1 = int(addr)
            addr2 = addr1
        addr2 += 1
        value = int(val)
        for a in range(addr1, addr2, step):
            snapshot[a] = value

    udg_array = skool.get_skool_udgs(x, y, width, height)
    frame = Frame(udg_array, options.scale)
    image_writer = ImageWriter()
    image_format = 'gif' if imgfname.lower()[-4:] == '.gif' else 'png'
    with open(imgfname, "wb") as f:
        image_writer.write_image([frame], f, image_format)
Exemple #10
0
 def _get_image_data(self, image_writer, udg_array, scale=1, mask=0, tindex=0, alpha=-1, x=0, y=0, width=None, height=None):
     frame = Frame(udg_array, scale, mask, x, y, width, height, tindex=tindex, alpha=alpha)
     img_stream = BytesIO()
     image_writer.write_image([frame], img_stream)
     img_bytes = [b for b in img_stream.getvalue()]
     img_stream.close()
     return img_bytes
    def _render_room(self, cwd, roomdata):
        # room_dims is not comprehendible to me right now .. could use a
        # worst-size case of the screen size

        room_width, room_height = 24, 16

        # Build a UDG array for the room

        udg_array = [[self._interior_tile(cwd, 0) for x in range(room_width)]
                     for y in range(room_height)]

        for obj_index, x, y in roomdata['objects']:
            interior_object_defs = 0x7095 + obj_index * 2
            objdef = self.snapshot[interior_object_defs] + self.snapshot[
                interior_object_defs + 1] * 256
            width, height, tiles = self._expand_object(cwd, objdef)

            tiles.reverse()

            for yy in range(height):
                for xx in range(width):
                    t = tiles.pop()
                    if t:
                        udg_array[y + yy][x + xx] = self._interior_tile(cwd, t)

        fname = '{ScreenshotImagePath}/room-%d' % roomdata['room_no']

        return self.handle_image(Frame(udg_array, 2), fname, cwd)
Exemple #12
0
def _parse_udg(snapshot, param_str):
    end, crop_rect, fname, frame, alt, params = skoolmacro.parse_udg(param_str)
    addr, attr, scale, step, inc, flip, rotate, mask, tindex, alpha, mask_addr, mask_step = params
    udgs = [[
        build_udg(snapshot, addr, attr, step, inc, flip, rotate, mask,
                  mask_addr, mask_step)
    ]]
    return Frame(udgs, scale, mask, *crop_rect, tindex=tindex, alpha=alpha)
Exemple #13
0
 def as_img(self, cwd, num, scale=2, mask=1, attr=120, udg_page=None, fname_suffix=''):
     mask_infix = 'm' if mask else 'u'
     udg_page_infix = udg_page if udg_page is not None else ''
     snapshot_name = self.get_snapshot_name()
     snapshot_infix = '_{0}'.format(snapshot_name) if snapshot_name else ''
     fname = 'as{0:03d}_{1}x{2}{3}{4}{5}{6}'.format(num & 255, attr, scale, mask_infix, udg_page_infix, snapshot_infix, fname_suffix)
     frame = Frame(lambda: self.build_sprite(num, attr, udg_page), scale, mask)
     alt = "Animatory state {}".format(num & 255)
     return self.handle_image([frame], fname, cwd, alt, 'AnimatoryStateImagePath')
def run(snafile, imgfname, options):
    snapshot = get_snapshot(snafile)
    game = ContactSamCruise(snapshot)
    x = y = 0
    width, height = 256, 42
    game.hide_chars()
    game.reset_fuses()
    game.switch_lights_on()
    game.raise_blinds()
    game.close_doors()
    game.adjust_rope(options.rope)

    if options.geometry:
        wh, xy = options.geometry.split('+', 1)
        width, height = [int(n) for n in wh.split('x')]
        x, y = [int(n) for n in xy.split('+')]

    for spec in options.place_char:
        values = []
        index = 0
        for n in spec.split(','):
            if not values and '.' in n:
                n, i = n.split('.', 1)
                try:
                    index = int(i)
                except:
                    pass
            try:
                values.append(int(n))
            except ValueError:
                values.append(None)
        game.place_char(*values[:5], index=index)

    for spec in options.pokes:
        addr, val = spec.split(',', 1)
        step = 1
        if '-' in addr:
            addr1, addr2 = addr.split('-', 1)
            addr1 = int(addr1)
            if '-' in addr2:
                addr2, step = [int(i) for i in addr2.split('-', 1)]
            else:
                addr2 = int(addr2)
        else:
            addr1 = int(addr)
            addr2 = addr1
        addr2 += 1
        value = int(val)
        for a in range(addr1, addr2, step):
            snapshot[a] = value

    udg_array = game.get_play_area_udgs(x, y, width, height)
    frame = Frame(udg_array, options.scale)
    image_writer = ImageWriter()
    image_format = 'gif' if imgfname.lower()[-4:] == '.gif' else 'png'
    with open(imgfname, "wb") as f:
        image_writer.write_image([frame], f, image_format)
Exemple #15
0
def run(infile, outfile, options):
    if options.binary or options.org is not None:
        snapshot = read_bin_file(infile, 49152)
        if options.org is None:
            org = 65536 - len(snapshot)
        else:
            org = options.org
        snapshot = [0] * org + list(snapshot) + [0] * (65536 - org -
                                                       len(snapshot))
    elif infile[-4:].lower() == '.scr':
        scr = read_bin_file(infile, 6912)
        snapshot = [0] * 65536
        snapshot[16384:16384 + len(scr)] = scr
    elif infile[-4:].lower() in ('.sna', '.szx', '.z80'):
        snapshot = get_snapshot(infile)
    else:
        try:
            snapshot = BinWriter(infile, fix_mode=options.fix_mode).snapshot
        except SkoolKitError:
            raise
        except:
            raise SkoolKitError(
                'Unable to parse {} as a skool file'.format(infile))

    for spec in options.moves:
        move(snapshot, spec)
    for spec in options.pokes:
        poke(snapshot, spec)

    if options.macro is not None:
        match = re.match('(#?)(FONT|SCR|UDG|UDGARRAY)([^A-Z]|$)',
                         options.macro)
        if match:
            macro = match.group(2)
            try:
                frame = MACROS[macro](snapshot, options.macro[match.end(2):])
            except skoolmacro.MacroParsingError as e:
                raise SkoolKitError('Invalid #{} macro: {}'.format(
                    macro, e.args[0]))
        else:
            raise SkoolKitError('Macro must be #FONT, #SCR, #UDG or #UDGARRAY')
    else:
        (x, y), (w, h) = options.origin, options.size
        frame = Frame(scr_udgs(snapshot, x, y, w, h), options.scale)

    if options.invert:
        for row in frame.udgs:
            for udg in row:
                if udg.attr & 128:
                    udg.data = [b ^ 255 for b in udg.data]
                    udg.attr &= 127

    flip_udgs(frame.udgs, options.flip)
    rotate_udgs(frame.udgs, options.rotate)

    _write_image(frame, outfile, options.animated)
    def map(self, cwd, addr, width, height, colour_supertiles, checkerboard):
        """ Get a UDG game map then save it and return an IMG element. """

        map_udgs = self._get_map_as_udgs(cwd, 0xBCEE, width, height,
                                         colour_supertiles, checkerboard)

        fname = '{ScreenshotImagePath}/map-%d-%d' % (colour_supertiles,
                                                     checkerboard)

        return self.handle_image(Frame(map_udgs), fname, cwd)
 def attribute_crash_img(self, cwd):
     self.push_snapshot()
     self.snapshot[59102:59105] = [2, 72, 17]
     cavern = self._get_cavern_udgs(58368)
     self.pop_snapshot()
     cavern[11][17] = cavern[11][18] = Udg(15, cavern[11][15].data)
     frame = Frame([row[14:22] for row in cavern[8:13]], 2)
     return self.handle_image([frame],
                              'attribute_crash',
                              cwd,
                              path_id='ScreenshotImagePath')
Exemple #18
0
    def _animate_conveyor(self, udgs, attr, direction, crop_rect, scale):
        mask = 0
        x, y, width, height = crop_rect
        delay = 10
        frame1 = Frame(udgs, scale, mask, x, y, width, height, delay)
        frames = [frame1]

        base_udg = None
        for row in udgs:
            for udg in row:
                if udg.attr == attr:
                    base_udg = udg
                    break
        if base_udg is None:
            return frames

        prev_udg = base_udg
        while True:
            next_udg = prev_udg.copy()
            data = next_udg.data
            if direction:
                data[0] = (data[0] >> 2) + (data[0] & 3) * 64
                data[2] = ((data[2] << 2) & 255) + (data[2] >> 6)
            else:
                data[0] = ((data[0] << 2) & 255) + (data[0] >> 6)
                data[2] = (data[2] >> 2) + (data[2] & 3) * 64
            if next_udg.data == base_udg.data:
                break
            next_udgs = []
            for row in udgs:
                next_udgs.append([])
                for udg in row:
                    if udg.attr == attr:
                        next_udgs[-1].append(next_udg)
                    else:
                        next_udgs[-1].append(udg)
            frames.append(Frame(next_udgs, scale, mask, x, y, width, height, delay))
            prev_udg = next_udg
        return frames
Exemple #19
0
 def expand_willy(self, text, index, cwd):
     # #WILLYroom,x,y,sprite[,left,top,width,height,scale](fname)
     names = ('room', 'x', 'y', 'sprite', 'left', 'top', 'width', 'height', 'scale')
     defaults = (0, 0, 32, 17, 2)
     end, crop_rect, fname, frame, alt, params = parse_image_macro(text, index, defaults, names)
     room, x, pixel_y, sprite, left, top, width, height, scale = params
     room_addr = 49152 + 256 * room
     room_udgs = self._get_room_udgs(room_addr, 1)
     willy = self._get_graphic(40192 + 32 * sprite, 7)
     room_bg = self.snapshot[room_addr + 160]
     self._place_graphic(room_udgs, willy, x, pixel_y, room_bg)
     img_udgs = [room_udgs[i][left:left + width] for i in range(top, top + min(height, 17 - top))]
     frames = [Frame(img_udgs, scale, 0, *crop_rect, name=frame)]
     return end, self.handle_image(frames, fname, cwd, alt, 'ScreenshotImagePath')
Exemple #20
0
 def expand_willy(self, text, index, cwd):
     # #WILLYcavern,x,y,sprite[,left,top,width,height,scale](fname)
     names = ('cavern', 'x', 'y', 'sprite', 'left', 'top', 'width', 'height', 'scale')
     defaults = (0, 0, 32, 17, 2)
     end, crop_rect, fname, frame, alt, params = parse_image_macro(text, index, defaults, names)
     cavern, x, pixel_y, sprite, left, top, width, height, scale = params
     cavern_addr = 45056 + 1024 * cavern
     cavern_udgs = self._get_cavern_udgs(cavern_addr, 0)
     willy = self._get_graphic(33280 + 32 * sprite, 7)
     cavern_bg = self.snapshot[cavern_addr + 544]
     self._place_graphic(cavern_udgs, willy, x, pixel_y, cavern_bg)
     img_udgs = [cavern_udgs[i][left:left + width] for i in range(top, top + min(height, 17 - top))]
     frames = [Frame(img_udgs, scale, 0, *crop_rect, name=frame)]
     return end, self.handle_image(frames, fname, cwd, alt, 'ScreenshotImagePath')
 def bottom_half_twice_img(self, cwd):
     cavern = self._get_cavern_udgs(64512)
     swordfish = self._get_graphic(45792, 1)
     cavern[5][19:21], cavern[6][19:21] = swordfish
     willy = self._get_graphic(33376, 1)
     cavern[2][19:21], cavern[3][19:21] = willy
     cavern[7][19:21] = willy[1]
     udgs = [row[18:22] for row in cavern[1:9]]
     for row in udgs:
         for udg in row:
             udg.attr = 1
     return self.handle_image(Frame(udgs, 2),
                              '{ScreenshotImagePath}/bottom_half_twice',
                              cwd)
    def decode_object(self, cwd, addr, index):
        width, height, tiles = self._expand_object(cwd, addr)

        tiles.reverse()

        # Build tile UDG array
        udg_array = []

        for y in range(height):
            udg_array.append([])  # start new row
            for _ in range(width):
                udg_array[-1].append(self._interior_tile(cwd, tiles.pop()))

        fname = '{ScreenshotImagePath}/object-%d' % index

        return self.handle_image(Frame(udg_array, 2), fname, cwd)
Exemple #23
0
 def expand_room(self, text, index, cwd):
     # #ROOMaddr[,scale,x,y,w,h,empty,fix,anim][{x,y,width,height}][(fname)]
     names = ('addr', 'scale', 'x', 'y', 'w', 'h', 'empty', 'fix', 'anim')
     defaults = (2, 0, 0, 32, 17, 0, 0, 0)
     end, crop_rect, fname, frame, alt, params = parse_image_macro(text, index, defaults, names)
     address, scale, x, y, w, h, empty, fix, anim = params
     if not fname:
         room_name = self.room_names[address // 256 - 192]
         fname = room_name.lower().replace(' ', '_')
     room_udgs = self._get_room_udgs(address, empty, fix)
     img_udgs = [room_udgs[i][x:x + w] for i in range(y, y + min(h, 17 - y))]
     if anim:
         attr = self.snapshot[address + 205]
         direction = self.snapshot[address + 214]
         frames = self._animate_conveyor(img_udgs, attr, direction, crop_rect, scale)
     else:
         frames = [Frame(img_udgs, scale, 0, *crop_rect, name=frame)]
     return end, self.handle_image(frames, fname, cwd, alt, 'ScreenshotImagePath')
    def _supertile_prime(self, cwd, addr, colour_supertiles, checkerboard):
        """ Return an image for the supertile at the specified address. """

        stile = (addr - 0x5B00) // 16

        # Build tile UDG array
        udg_array = []

        for i in range(4 * 4):
            if i % 4 == 0:
                udg_array.append([])  # start new row
            bright = ((i // 4) & 1 ^ i & 1) if checkerboard else False
            tile = self._tile(cwd, self.snapshot[addr + i], stile,
                              colour_supertiles, bright)
            udg_array[-1].append(tile)

        fname = '{ScreenshotImagePath}/supertile-%X-%d-%d' % (
            stile, colour_supertiles, checkerboard)

        return self.handle_image(Frame(udg_array, 2), fname, cwd)
Exemple #25
0
def _parse_udgarray(snapshot, param_str):
    end, crop_rect, fname, frame, alt, params = skoolmacro.parse_udgarray(
        param_str, 0, snapshot, False)
    udg_array, scale, flip, rotate, mask, tindex, alpha = params
    udgs = adjust_udgs(udg_array, flip, rotate)
    return Frame(udgs, scale, mask, *crop_rect, tindex=tindex, alpha=alpha)
 def _decode_and_save_mask(self, cwd, addr, suggested_width,
                           suggested_height):
     udg_array = self._decode_mask(cwd, addr, suggested_width,
                                   suggested_height)
     fname = '{ScreenshotImagePath}/mask-%.4X' % addr
     return self.handle_image(Frame(udg_array, 2), fname, cwd)
Exemple #27
0
 def mutable(self, cwd, address, padding=0):
     fname = 'mutable{0}_{1}'.format(address, padding) if padding else 'mutable{0}'.format(address)
     frame = Frame(lambda: self.get_mutable_udg_array(address, padding), 2)
     return self.handle_image([frame], fname, cwd, path_id='MutableImagePath')
Exemple #28
0
 def play_area(self, cwd, fname, x, y, w=1, h=1, scale=2, show_chars=0, show_x=0):
     frame = Frame(lambda: self.get_skool_udgs(x, y, w, h, show_chars, show_x), scale)
     return self.handle_image([frame], fname, cwd, path_id='PlayAreaImagePath')
Exemple #29
0
def _parse_scr(snapshot, param_str):
    end, crop_rect, fname, frame, alt, params = skoolmacro.parse_scr(param_str)
    scale, x, y, w, h, df, af, tindex, alpha = params
    udgs = scr_udgs(snapshot, x, y, w, h, df, af)
    return Frame(udgs, scale, 0, *crop_rect, tindex=tindex, alpha=alpha)
Exemple #30
0
 def font(self, cwd, address, num_chars=96, scale=2, fname='font'):
     width = scale * (sum(self.snapshot[address:address + num_chars]) + num_chars + 1)
     frame = Frame(lambda: self._font_udgs(address, num_chars), scale, width=width)
     return self.handle_image([frame], fname, cwd, path_id='FontImagePath')