コード例 #1
0
class PlayScene:
    def __init__(self):
        self.next = self

        self.session = Session()
        self.player = Sprite('player')
        self.player = Sprite('player')
        self.sprites = [self.player]
        self.last_color = None
        self.sprites_by_row = None
        self.lifetime = 0

        # Forgive me father for I am about to sin.
        m = [
            'xx xx xx xx xx xx xx xx c7 c8 c8 c8 c8 c8 c8 c8 c8 c8 c9 xx xx xx xx xx xx xx xx',
            'c7 c8 c8 c8 c8 c8 c9 xx c4 c5 c5 c5 c5 c5 c5 c5 c5 c5 c6 xx c7 c8 c8 c8 c8 c8 c9',
            'c4 c5 c5 c5 c5 c5 c6 xx c4 f7 f8 f8 f8 f8 f8 f8 f8 f9 c6 xx c4 c5 c5 c5 c5 c5 c6',
            'c4 f7 f8 f8 f8 f9 C1 c8 C3 f4 f5 f5 f5 f5 f5 f5 f5 f6 C1 c8 C3 f7 f8 f8 f8 f9 c6',
            'c4 f4 f5 f5 f5 f6 c5 c5 c5 f4 f5 f5 f5 f5 f5 f5 f5 f6 c5 c5 c5 f4 f5 f5 f5 f6 c6',
            'c4 f4 f5 f5 f5 F1 f8 f8 f8 F3 f5 f5 f5 f5 f5 f5 f5 F1 f8 f8 f8 F3 f5 f5 f5 f6 c6',
            'c4 f4 f5 f5 f5 F7 f2 f2 f2 F9 f5 f5 f5 f5 f5 f5 f5 F7 f2 f2 f2 F9 f5 f5 f5 f6 c6',
            'c4 f4 f5 f5 f5 f6 C7 c2 C9 f4 f5 f5 f5 f5 f5 f5 f5 f6 C7 c2 C9 f4 f5 f5 f5 f6 c6',
            'c4 tl ct ct ct tr c6 xx c4 f4 f5 f5 f5 f5 f5 f5 f5 f6 c6 xx c4 tl ct ct ct tr c6',
            'c4 bl cb cb cb br c6 xx c4 f4 f5 f5 f5 f5 f5 f5 f5 f6 c6 xx c4 bl cb cb cb br c6',
            'c4 f4 f5 f5 f5 f6 c6 xx c4 f4 f5 f5 f5 f5 f5 f5 f5 f6 c6 xx c4 f4 f5 f5 f5 f6 c6',
            'c4 f4 f5 f5 f5 f6 c6 xx c4 f4 f5 f5 f5 f5 f5 f5 f5 f6 c6 xx c4 f4 f5 f5 f5 f6 c6',
            'c4 f4 f5 f5 f5 f6 c6 xx c4 f4 f5 f5 f5 f5 f5 f5 f5 f6 c6 xx c4 f4 f5 f5 f5 f6 c6',
            'c4 f1 f2 f5 f2 f3 c6 xx c4 f1 f2 f2 f2 f2 f2 f2 f2 f3 c6 xx c4 f1 f2 f5 f2 f3 c6',
            'c1 c2 c2 dd c2 c2 c3 xx c1 c2 c2 c2 c2 c2 c2 c2 c2 c2 c3 xx c1 c2 c2 dd c2 c2 c3'
        ]

        # Transpose this
        cols = []
        row_count = len(m)
        col_count = len(m[0].split())
        for i in range(len(m)):
            m[i] = m[i].split()
        x = 0
        while x < col_count:
            col = []
            y = 0
            while y < row_count:
                col.append(Tile(m[y][x]))
                y += 1
            x += 1
            cols.append(col)

        self.grid = cols

        for i in range(5):
            v = self.grid[1 + i][8]
            h = self.grid[21 + i][8]
            v.is_counter = True
            h.is_counter = True
            v.counter_slot = i
            h.counter_slot = i
            v.counter_is_hero = False
            h.counter_is_hero = True

        self.player.x = 14.5
        self.player.y = 12.5

        #self.set_up_boxes(10)
        self.session.order_more('red', True)

    def place_box(self, key):
        storage_left = 11
        storage_width = 5
        storage_top = 2
        storage_height = 5

        box = Box(key)
        while True:
            x = storage_left + int(random.random() * storage_width)
            y = storage_top + int(random.random() * storage_height)
            dx = abs(x - self.player.x)
            dy = abs(y - self.player.y)
            if dx > 2 or dy > 2:
                break

        tile = self.grid[x][y]
        if tile.stack == None:
            tile.stack = []
        tile.stack.append(box)

    def create_random_boxes(self, count):
        storage_left = 11
        storage_width = 5
        storage_top = 2
        storage_height = 5

        output = []

        for i in range(count):
            box = self.session.get_random_box(True)
            x = int(random.random() * storage_width) + storage_left
            y = int(random.random() * storage_height) + storage_top

            output.append([box, x, y])

        return output

    def set_up_boxes(self, count):
        boxes = self.create_random_boxes(count)
        for box in boxes:
            b = box[0]
            x = box[1]
            y = box[2]
            tile = self.grid[x][y]
            if tile.stack == None:
                tile.stack = []
            tile.stack.append(b)

    def incorrect_order(self):
        play_sound("incorrect_order")
        pass

    def lift(self, is_full):
        dxdy = _direction_to_vector[self.player.direction]
        x = int(self.player.x) + dxdy[0]
        y = int(self.player.y) + dxdy[1]
        tile = self.grid[x][y]

        if self.player.holding == None:
            if tile.stack != None and not tile.is_counter:
                if is_full:
                    self.player.holding = tile.stack
                    tile.stack = None
                else:
                    self.player.holding = [tile.stack[-1]]
                    if len(tile.stack) == 1:
                        tile.stack = None
                    else:
                        tile.stack = tile.stack[:-1]
                play_sound('lift')
        else:
            fix_loc = False
            if not tile.passable and not tile.is_counter:
                play_sound('cant_drop_box')
                return

            to_drop = []

            if is_full:
                to_drop = self.player.holding[:]
            else:
                to_drop = self.player.holding[:1]

            item_sold = False

            if tile.is_counter:
                for sprite in self.sprites:
                    if sprite.phase == 4:
                        if sprite.counter_slot == tile.counter_slot:
                            if sprite.is_hero == tile.counter_is_hero:
                                sprite_demands = sprite.demands[:]
                                for item_to_drop in to_drop:
                                    found = False
                                    i = 0
                                    while i < len(sprite_demands):
                                        d = sprite_demands[i]
                                        if d == item_to_drop.key:
                                            found = True
                                            sprite_demands = sprite_demands[:i] + sprite_demands[
                                                i + 1:]
                                            break
                                        i += 1
                                    if not found:
                                        self.incorrect_order()
                                        return
                                self.session.item_sold(sprite,
                                                       item_to_drop.key)
                                item_sold = True
                                break

            if item_sold:
                play_sound('money_sound')
            elif tile.is_counter:
                # can't drop a box on a counter without selling it
                return
            else:
                play_sound('drop')
            if tile.stack == None:
                fix_loc = True
                tile.stack = []

            if is_full:
                for item in self.player.holding:
                    tile.stack.append(item)
                self.player.holding = None
            else:
                tile.stack.append(self.player.holding[0])
                if len(self.player.holding) == 1:
                    self.player.holding = None
                else:
                    self.player.holding = self.player.holding[1:]

            # player could possibly set a box down and then be standing in an invalid position
            # nudge the player closer to the center of his tile to prevent this invalid state
            if fix_loc:
                if self.player.direction == 'left' or self.player.direction == 'right':
                    left = self.player.direction == 'left'
                    attempts = 10
                    while self.player.is_overlapping(left) and attempts > 0:
                        cx = int(self.player.x) + 0.5
                        #cy = int(self.player.y) + 0.5 if (not horizontal) else self.player.y
                        self.player.x = cx * .3 + self.player.x * .7
                        #self.player.y = cy * .3 + self.player.y * .7
                        attempts -= 1

                    if attempts == 0:  # my paranoia of some bug causing an infinite loop here
                        self.player.x = int(self.player.x) + 0.5
                        self.player.y = int(self.player.y) + 0.5

    def process_input(self, events, pressed_keys):
        for event in events:
            if event.down:
                if event.action == 'full' or event.action == 'single':
                    self.lift(event.action == 'full')
                elif event.action == 'menu':
                    self.next = PriceMenu(self)
                elif event.action == 'order':
                    self.next = OrderStuffMenu(self)
                elif event.action == 'pause':
                    self.next = PauseMenu(self)

        v = 1.3
        dx = 0
        dy = 0
        if pressed_keys.get('left'):
            dx = -1
        elif pressed_keys.get('right'):
            dx = 1
        if pressed_keys.get('up'):
            dy = -1
        elif pressed_keys.get('down'):
            dy = 1
        self.player.try_move(dx, dy)

    def lose_scene(self, type):
        self.next = DefeatScene(type, int(self.lifetime / 30.0),
                                self.session.budget, self.session.things_sold)

    def update(self, counter):
        self.lifetime += 1
        ensure_playing('shopmusic')
        self.session.update()

        # TODO: pause movement, make a noise while brining attention to the balance meter, and then move to the defeat screen a second later
        # probably done with a simple transition scene
        balance = self.session.is_defeat()
        if balance != 0:
            if balance == -1:
                type = 'hero_win'
            else:
                type = 'villain_win'
            self.lose_scene(type)
            return

        if len(self.session.get_disgruntled_count(True)) > 6:
            self.lose_scene('hero_angry')
            return
        elif len(self.session.get_disgruntled_count(False)) > 6:
            self.lose_scene('villain_angry')
            return

        if counter % 10 == 0:
            r = self.session.pop_restocking()
            if r != None:
                self.place_box(r)

        c = self.session.get_last_available_color()
        if c != self.last_color:
            self.last_color = c
            self.next = NewProductsMenu(self, c)
        customers = self.session.check_for_customers()

        if customers != None:
            for customer in customers:
                is_hero = customer.is_hero
                taken = {}
                for i in range(5):
                    taken[i] = False
                for sprite in self.sprites:
                    if sprite != self.player and sprite.is_hero == is_hero:
                        taken[sprite.counter_slot] = True
                open = []
                for k in taken.keys():
                    if not taken[k]:
                        open.append(k)
                random.shuffle(open)

                if (len(open) > 0):
                    customer.set_counter_slot(open[0])
                    self.sprites.append(customer)
                else:
                    # counter full. reject customer
                    self.session.reject_last_customer()

        for sprite in self.sprites:
            if sprite != self.player:
                sprite.automate(self.grid, self.session)

        new_sprites = []
        for sprite in self.sprites:
            if not sprite.destroy_me:
                sprite.update(self.grid, self.sprites)
                new_sprites.append(sprite)
        self.sprites = new_sprites

    def render2(self, screen, counter):
        _LEFT2 = _LEFT * 2
        _TOP2 = _TOP * 2
        spacing = 28
        for sprite in self.sprites:
            if sprite != self.player:
                if sprite.phase == 4:
                    slot = sprite.counter_slot
                    demand_x = int(16 * sprite.x - 8) * 2 - 2 + _LEFT2
                    demand_y = int(16 * sprite.y) * 2 + _TOP2

                    img = get_image('misc/demand_bubble')
                    screen.blit(img, (demand_x, demand_y))
                    demands = sprite.demands
                    height = len(demands) * spacing
                    icon_y = demand_y + img.get_height(
                    ) // 2 - height // 2 - 30 + 2 + spacing * 3 // 2
                    icon_x = demand_x + 8 + 2
                    for d in demands:
                        screen.blit(get_image('boxes/' + d), (icon_x, icon_y))
                        icon_y += spacing

                    gbarx = demand_x + 4
                    gbary = demand_y + img.get_height() + 8
                    gbarw = img.get_width() - 8
                    percent = 1.0 * sprite.gruntles / STARTING_GRUNTLES_COUNT
                    gbarw0 = max(1, int(gbarw * percent))
                    gbarh = 3

                    if percent < 0.3: color = (255, 0, 0)
                    elif percent > 0.7: color = (0, 220, 0)
                    else: color = (255, 255, 0)

                    pygame.draw.rect(
                        screen, (0, 0, 0),
                        pygame.Rect(gbarx - 1, gbary - 1, gbarw + 2,
                                    gbarh + 2))
                    pygame.draw.rect(screen, color,
                                     pygame.Rect(gbarx, gbary, gbarw0, gbarh))

        self.draw_budget_bar(screen)
        self.draw_power_balance(screen)
        self.draw_options(screen)

        screen.blit(get_image('misc/radio'), (529, 615))

        for is_hero in (False, True):
            x = 717 if is_hero else 86
            y = 640
            i = 0
            x += 6
            sprite_types = self.session.get_disgruntled_count(is_hero)
            while i < 6:
                sprite_type = None if (
                    i >= len(sprite_types)) else sprite_types[i]

                if sprite_type != None:
                    img = get_image('fwownyface/' + sprite_type)
                    screen.blit(img, (x, y))

                pygame.draw.rect(screen, (0, 0, 0),
                                 pygame.Rect(x - 3, y - 3, 22, 22), 1)

                i += 1
                x += 28

    def draw_options(self, screen):

        prices = get_small_text("Adjust prices (R)")
        order_more = get_small_text("Restock (T)")
        cloud = get_image('misc/thought_cloud')
        x = screen.get_width() - cloud.get_width() - 20
        y = 0
        screen.blit(cloud, (x, y))
        screen.blit(prices, (x + 73, y + 40))
        screen.blit(order_more, (x + 73, y + 70))

    def draw_power_balance(self, screen):
        left = 416
        top = 564
        text = get_small_text("Power Balance")
        screen.blit(text, (left, top))

        width = 220
        y = top + text.get_height() + 10
        x = left + text.get_width() // 2 - width // 2

        evil = int(self.session.balance * width)
        good = width - evil
        height = 20
        border = 3
        pygame.draw.rect(
            screen, (123, 123, 123),
            pygame.Rect(x - border, y - border, width + border * 2,
                        height + border * 2))
        pygame.draw.rect(screen, (0, 0, 0), pygame.Rect(x, y, evil, height))
        x += evil
        pygame.draw.rect(screen, (255, 255, 255),
                         pygame.Rect(x, y, good, height))

    def draw_budget_bar(self, screen):
        screen.blit(get_image('misc/budget_bar'), (10, 10))
        screen.blit(get_text("Budget: " + format_money(self.session.budget)),
                    (30, 38))

    def render1(self, screen, rcounter):
        screen.fill((100, 180, 255))
        self.render_room(screen, (_LEFT, _TOP), rcounter)

    def render_room(self, screen, roomtopleft, rcounter):
        rows = len(self.grid[0])
        cols = len(self.grid)
        grid = self.grid

        left = roomtopleft[0]
        top = roomtopleft[1]

        if self.sprites_by_row == None:
            i = 0
            self.sprites_by_row = []
            while i < rows:
                self.sprites_by_row.append([])
                i += 1

        i = 0
        while i < rows:
            self.sprites_by_row[i] = []
            i += 1

        for sprite in self.sprites:
            row = int(sprite.y)
            if row >= 0 and row < rows:
                self.sprites_by_row[row].append(sprite)

        row = 0
        while row < rows:
            col = 0
            while col < cols:
                tile = self.grid[col][row]
                img = tile.image
                if img != None:
                    screen.blit(img, (col * 16 + left, row * 16 + top))
                    if tile.stack != None:
                        i = 0
                        x = col + 0.5
                        y = row + 0.5
                        for box in tile.stack:
                            box.render(screen, left, top, x, y, i)
                            i += 1
                col += 1

            for sprite in self.sprites_by_row[row]:
                sprite.render(screen, left, top, rcounter)
                if sprite.holding != None:
                    i = 4.7
                    for box in sprite.holding:
                        box.render(screen, left, top, sprite.x, sprite.y, i)
                        i += 1
            row += 1