Пример #1
0
    def __init__(self, count, pos_x, pos_y, *groups):
        if count > 1:
            label = "%d" % count
        else:
            label = ""

        pos_y -= 2

        spr = data.load_image("ghost.png")
        w, h = spr.get_size()

        fnt = data.load_image("digits.png")
        fnt_w = 4
        fnt_h = 5

        txt_x = w + 1
        txt_y = 2

        self.image = pygame.Surface((txt_x + fnt_w * len(label), h),
                                    pygame.SRCALPHA)
        self.image.blit(spr, (0, 0))
        for i, c in enumerate(label):
            fnt_x = int(c) * fnt_w
            self.image.blit(fnt, (txt_x + i * fnt_w, txt_y),
                            (fnt_x, 0, fnt_w, fnt_h))

        self.rect = pygame.Rect(pos_x, pos_y, *self.image.get_size())
        self.targ_y = pos_y - DEAD_TTL // 2

        pygame.sprite.Sprite.__init__(self, *groups)
Пример #2
0
    def draw(self, m):
        self.buf = pygame.Surface((m.width * GRID_W, m.height * GRID_H))
        self.buf.fill(0)

        for (x, y), c in m.grid.items():
            self.buf.blit(self.tls.get("field"), (x * GRID_W, y * GRID_H))

        for x in range(m.width):
            for y in range(m.height):
                c = m.grid[x, y]
                if c.view == "field":
                    continue
                self.draw_one(x, y, c)
Пример #3
0
def main(init_mode=title.Title):
    pygame.mixer.pre_init(44100)
    pygame.init()
    pygame.mixer.set_num_channels(32)
    mouse.init()

    music.load()
    music.reset("major")
    music.play()

    pygame.display.set_caption(GAME_NAME)

    pygame.mouse.set_visible(False)

    size = SCREEN_W * SCALE_FACTOR, SCREEN_H * SCALE_FACTOR

    disp = pygame.display.set_mode(size, DOUBLEBUF)
    temp = pygame.Surface((SCREEN_W, SCREEN_H))
    uibg = data.load_image("uibg.png")

    mode = init_mode()

    while mode is not None:
        for ev in pygame.event.get():
            if ev.type == QUIT:
                return

            if ev.type == pygame.MOUSEBUTTONUP:
                mode.handle_click(ev)

        temp.fill(SCREEN_BG)
        temp.blit(uibg, (0, GRID_MAX_H * GRID_H + 1))

        mode = mode.update(temp)
        mouse.draw(temp)
        pygame.transform.scale(temp, disp.get_size(), disp)
        pygame.display.flip()

    print "Bye."
Пример #4
0
    def __init__(self, name):
        self.name = name
        self.conf = data.load_json(name)
        self.surf = data.load_image(self.conf["image"])

        self.tiles = defaultdict(list)
        self.dummy = pygame.Surface((GRID_W, GRID_H))
        self.dummy.fill((255, 0, 0))

        for name, coords in self.conf["tiles"].items():
            for ix, iy in coords:
                x = ix * GRID_W
                y = iy * GRID_H
                tile = pygame.Surface((GRID_W, GRID_H), SRCALPHA)
                tile.blit(self.surf, (0, 0), (x, y, GRID_W, GRID_H))
                self.tiles[name].append(tile)

        if pygame.version.vernum >= (2, 0, 0):
            # pygame_sdl2 has trouble with auto-generate stuff below, so we skip it
            return

        gen = defaultdict(list)

        # straits
        for tile in self.tiles["road-hh"]:
            tile = pygame.transform.flip(tile, True, False)
            gen["road-hh"].append(tile)
            tile = pygame.transform.flip(tile, False, True)
            gen["road-hh"].append(tile)
            tile = pygame.transform.flip(tile, True, False)
            gen["road-hh"].append(tile)

        for tile in self.tiles["road-vv"]:
            tile = pygame.transform.flip(tile, True, False)
            gen["road-vv"].append(tile)
            tile = pygame.transform.flip(tile, False, True)
            gen["road-vv"].append(tile)
            tile = pygame.transform.flip(tile, True, False)
            gen["road-vv"].append(tile)

        # turns
        for tile in self.tiles["road-tl"]:
            tile = pygame.transform.rotate(tile, 90)
            gen["road-bl"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-br"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-tr"].append(tile)

        for tile in self.tiles["road-tr"]:
            tile = pygame.transform.rotate(tile, 90)
            gen["road-tl"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-bl"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-br"].append(tile)

        for tile in self.tiles["road-br"]:
            tile = pygame.transform.rotate(tile, 90)
            gen["road-tr"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-tl"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-bl"].append(tile)

        for tile in self.tiles["road-bl"]:
            tile = pygame.transform.rotate(tile, 90)
            gen["road-br"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-tr"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-tl"].append(tile)

        # dead-ends
        for tile in self.tiles["road-bb"]:
            tile = pygame.transform.rotate(tile, 90)
            gen["road-rr"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-tt"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-ll"].append(tile)

        # tees
        for tile in self.tiles["road--t"]:
            tile = pygame.transform.rotate(tile, 90)
            gen["road-|l"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road--b"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-|r"].append(tile)

        for tile in self.tiles["road-|l"]:
            tile = pygame.transform.rotate(tile, 90)
            gen["road--b"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road-|r"].append(tile)
            tile = pygame.transform.rotate(tile, 90)
            gen["road--t"].append(tile)

        for name, tiles in gen.items():
            self.tiles[name].extend(tiles)
Пример #5
0
    def get_wall_color(self, cell, dx, dy):
        return (255, 255, 255) if cell.walls.get((dx, dy)) else (0, 0, 0)

if __name__ == '__main__':
    from sim import Map
    pygame.init()
    disp = pygame.display.set_mode((800, 600), DOUBLEBUF)
    clock = pygame.time.Clock()
    font = pygame.font.Font(pygame.font.get_default_font(), 16)

    model = Map()
    model.load("level1")

    renderer = Renderer()
    buf = pygame.Surface(disp.get_size())

    while 1:
        clock.tick(6000)
        for _ in range(0, 2):
            x, y = model.update()
            renderer.draw_one(model, x, y, buf)
        disp.blit(buf, (0, 0))
        disp.blit(fps, (600, 2))

        if model.census:
            cnc = font.render("%.2f / %.2f / %.2f" % (model.census.good, model.census.sick, model.census.dead), True, (255, 255, 255))
            disp.blit(cnc, (600, 18))

        pygame.display.flip()
Пример #6
0
class Game (object):
    text_color = (255, 255, 255)

    cell_highlight_image = pygame.Surface((GRID_W, GRID_H), pygame.SRCALPHA);
    cell_highlight_image.fill((0xff, 0xff, 0xff, 0x33), (0, 0, GRID_W, GRID_H))

    select_voices = [
        "voices/sel1.wav",
        "voices/sel2.wav",
        "voices/sel3.wav",
        "voices/sel4.wav",
        "voices/sel5.wav",
        "voices/sel6.wav",
    ]

    ack_voices = [
        "voices/ack1.wav",
        "voices/ack2.wav",
        "voices/ack3.wav",
        "voices/ack4.wav",
    ]

    def __init__(self, m):
        self.model = m

        self.units = [unit.Unit(self.model, x, y) for x, y in self.model.conf.units]

        self.all_effects = pygame.sprite.Group()
        self.individual_effects = defaultdict(pygame.sprite.Group)
        self.all_walkers = pygame.sprite.Group()

        self.renderer = render.Renderer()
        self.renderer.draw(self.model)

        self.clock = pygame.time.Clock()

        # Win conditions
        self.win_duration_sec    = self.model.conf.game["duration"]
        self.win_duration_frames = self.model.conf.game["duration"] * FRAMES_PER_SECOND
        self.win_living_min_threshold  = self.model.conf.game["living_min_threshold"]

        self.font = bont.Tiny()
        self.news_font = data.load_font(*NEWS_FONT)
        self.over_font = data.load_font(*OVER_FONT)
        self.selection = None
        self.last_selection = None
        self.need_destination = False
        self.pending_cmd = None

        self.buttons = buttons.ButtonRegistry()

        self.buttons.add_sprite_button("Cleanse", self.send_reap, 150, 160)
        self.buttons.add_sprite_button("Burn", self.send_burn, 150, 180)
        self.buttons.add_sprite_button("Block", self.send_block, 205, 160)
        self.buttons.add_sprite_button("Cancel", self.cancel_selection, 205, 180)

        self.advisor_face = data.load_image("faces/6p.png")

        self.frame = 0
        self.newsflash = None
        # don't fire a newsflash right away
        self.next_newsflash = 5 * FRAMES_PER_SECOND

        self.hover_info = hover_info.HoverInfo()

        self.over = None
        self.paused = False
        self.final_click = False

        self.voice_chan = None
        self.select_voice_iter = itertools.cycle(self.select_voices)

        music.enqueue("minor1")

    def set_pending_cmd(self, cmd):
        mouse.set_cursor("target", 160)
        self.newsflash = newsflash.Unit(cmd[0])
        self.need_destination = True
        self.pending_cmd = cmd

    def unset_pending_cmd(self):
        mouse.set_cursor("default")
        self.need_destination = False
        self.pending_cmd = None
        self.buttons.unset_pending_button()
        self.newsflash = None

    def execute_pending_cmd(self, dst):
        x, y = dst
        self.unblock_cell()
        self.selection.set_command("move", x, y, self.pending_cmd)
        data.load_sample(random.choice(self.ack_voices)).play()
        self.unset_pending_cmd()
        self.selection = None

    def send_reap(self):
        if not self.selection:
            return
        self.set_pending_cmd(("reap", self.model.grid))

    def send_burn(self):
        if not self.selection:
            return
        self.set_pending_cmd(("burn", self.model.grid))

    def send_block(self):
        if not self.selection:
            return
        self.set_pending_cmd(("block", self.model.grid))

    def cancel_selection(self):
        self.selection = None
        self.unset_pending_cmd()

    def unblock_cell(self):
        unit = self.selection
        unit.is_blocking = False
        x, y = self.find_cell((unit.x, unit.y))
        for u in self.units:
            if not u.is_blocking:
                continue
            ux, uy = self.find_cell((u.x, u.y))
            if ux == x and uy == y:
                return
        self.model.grid[x, y].unblock()

    def find_unit(self, pos):
        for unit in self.units:
            if unit.rect.collidepoint(pos):
                return unit
        return None

    def find_cell(self, pos):
        x, y = pos
        return int(x / self.renderer.stride_x), int(y / self.renderer.stride_y)

    def handle_click(self, ev):
        mx, my = ev.pos
        pos = mx // SCALE_FACTOR, my // SCALE_FACTOR

        if self.over is not None:
            self.final_click = True

        if self.paused:
            # unpause and finish newsflash
            if self.newsflash is not None:
                self.newsflash.show = 1
            self.paused = False
            return

        if self.selection:
            if self.buttons.process_click(pos):
                return

            if self.need_destination:
                self.newsflash = None
                dst = self.find_cell(pos)
                self.execute_pending_cmd(dst)
                return

        if self.selection:
            self.newsflash = None

        self.selection = self.find_unit(pos)

        if self.selection:
            if not self.voice_chan or not self.voice_chan.get_busy():
                if self.selection != self.last_selection:
                    self.select_voice_iter = itertools.cycle(self.select_voices)
                self.voice_chan = data.load_sample(next(self.select_voice_iter)).play()
                self.last_selection = self.selection

            self.newsflash = newsflash.Unit("prompt")
        else:
            self.last_selection = None

    def update_one(self):
        dx, dy, new_dead, new_sick, caught_fire = self.model.update()
        cell = self.model.grid[dx, dy]
        self.individual_effects[dx, dy].update()
        if new_dead > 0 and cell.view != "field":
            effects.Ghost(new_dead, dx * GRID_W, dy * GRID_H, self.all_effects, self.individual_effects[dx, dy])
        if new_sick > 0:
            effects.Infection(dx * GRID_W, dy * GRID_H, self.all_effects, self.individual_effects[dx, dy])
        if caught_fire:
            effects.Fire(dx * GRID_W, dy * GRID_H, self.all_effects, self.individual_effects[dx, dy])
        

        flow_dir = max(cell.incoming_acu.keys(), key=lambda d: cell.incoming_acu[d])
        if cell.incoming_acu[flow_dir] >= POP_FLOW_ALIVE_NR_TRIGGER:
            dirx, diry = flow_dir
            # Shift animation to the cell-origin of the flow
            dx, dy = dx - dirx, dy - diry
            # Do not fire up more than one animation effect at the same time
            if len(self.individual_effects[dx, dy]) == 0 and random.random() <= POP_FLOW_PROBABILiTY_TRIGGER:
                effects.Walker(dx * GRID_W, dy * GRID_H, dirx, diry, self.all_effects, self.individual_effects[dx, dy])
            cell.incoming_acu[flow_dir] = 0.0

    def update_music(self):
        census = self.model.census

        if census is None:
            music.update(1.0)
            return

        if census.alive > 1.0:
            music.update(1 - min(1, max(0, census.good / census.alive)))
        else:
            music.update(0.0)

        not_good = census.not_good

        if census.good > not_good * 3:
            music.enqueue("minor1")
        elif census.good > census.sick * 2:
            music.enqueue("minor2")
        else:
            music.enqueue("diminished")

    def update(self, disp):
        census = self.model.census
        self.update_music()

        if not self.paused and self.over is None:
            self.frame += 1

        self.clock.tick(FRAMES_PER_SECOND)

        if self.over is None and not self.paused:
            # let the doc warp to the starting location
            if self.frame > 1:
                if len(self.model.conf.messages) > 0:
                    self.play_level_message()

            if census is not None:
                # Determine the game outcome: win or defeat
                if (census.good + census.sick) < self.win_living_min_threshold:
                    self.cancel_selection()
                    self.newsflash = newsflash.Loss(self.win_living_min_threshold, census)
                    self.over = False
                elif self.frame >= self.win_duration_frames:
                    self.cancel_selection()
                    self.newsflash = newsflash.Victory(census)
                    self.over = True

            for _ in range(0, UPDATES_PER_FRAME):
                self.update_one()

        self.renderer.blit(disp)
        self.all_effects.draw(disp)

        self.draw_stats(disp)

        self.draw_newsflash(disp, census)

        for unit in self.units:
            if not self.paused:
                unit.update()
            if not self.paused and self.over is None and unit.command[0] == unit.cmd_reap and random.random() > 0.96:
                effects.Plus(unit.x * GRID_W, unit.y * GRID_H, self.all_effects, self.individual_effects[unit.x, unit.y])
            unit.draw(disp, self.selection == unit, self.paused)

        if self.over is not None:
            if self.over:
                music.switch("major")
                self.draw_game_over(disp, "SUCCESS", TO_NEXT_LEVEL if self.model.conf.next_level else BACK_TO_MENU)
                    
                if self.final_click:
                    n = self.model.next_level()
                    if n is not None:
                        return Game(n)
                    return title.Title()
            else:
                music.switch("diminished")
                self.draw_game_over(disp, "GAME OVER", BACK_TO_MENU)
                return self if not self.final_click else title.Title()

        if self.selection:
            self.buttons.draw(disp)

        self.draw_cell_hover(disp)

        return self

    def draw_game_over(self, targ, text, subtext):
        t = self.over_font.render(text, True, self.text_color)
        w, h = t.get_size()
        sw, sh = SCREEN_W, SCREEN_H - 40
        targ.blit(t, (sw / 2 - w / 2, sh / 2 - h / 2))

        w = self.font.get_width(subtext)
        self.font.render(targ, subtext, (sw / 2 - w / 2, sh / 2 + h))

    def draw_text(self, targ, text, pos):
        self.font.render(targ, text, pos)

    def draw_stats(self, targ):
        curr_time = self.frame / FRAMES_PER_SECOND
        self.time_to_cure = self.win_duration_sec - curr_time
        self.draw_text(targ, " ttl: %5.0f" % self.time_to_cure, (196, 2))
        self.draw_text(targ, "save: %5.0f" % self.win_living_min_threshold, (196, 12))

    def draw_population(self, targ, pop):
        if pop is None:
            return
        cnc_text = "%.2f / %.2f / %.2f" % (pop.good, pop.sick, pop.dead)
        self.draw_text(targ, cnc_text, (2, 160))

    def draw_newsflash(self, targ, pop):
        news = self.newsflash
        if news is not None:
            news.advance()
            news.draw(targ)
            if news.finished:
                self.newsflash = None
            return

        if self.frame >= self.next_newsflash and pop is not None:
            self.newsflash = newsflash.Random(pop, self.time_to_cure)
            self.next_newsflash = self.frame + random.randint(1 * FRAMES_PER_SECOND, 5 * FRAMES_PER_SECOND)

    def draw_cell_hover(self, targ):
        (mx, my) = pygame.mouse.get_pos()
        mpos = mx // SCALE_FACTOR, my // SCALE_FACTOR
        cpos = self.find_cell(mpos)

        if cpos not in self.model.grid:
            return

        (cx, cy) = cpos[0] * GRID_W, cpos[1] * GRID_H
        cell = self.model.grid[cpos]

        highlight_cell = True   # TODO This mode may depend on a game state
        if highlight_cell:
            targ.blit(self.cell_highlight_image, (cx, cy, 0, 0))

        show_cell_stats = True  # TODO This mode may depend on a game state
        if show_cell_stats:
            x, y = (cx, cy) if STICK_HOVER_INFO_TO_CELL else mpos
            self.hover_info.draw(x, y, cell.pop, targ)

    def play_level_message(self):
        game_time = self.frame / FRAMES_PER_SECOND
        if not self.newsflash:
            message = self.model.conf.messages[0]
            if game_time > int(message["min_time"]):
                self.model.conf.messages.pop(0)
                self.paused = True
                def finished_cb():
                    self.paused = False

                self.newsflash = newsflash.LevelMessage(message["face"], message["name"], message["msg"], finished_cb)