Ejemplo n.º 1
0
class Engine:
    def __init__(self, stdscr, objects):
        self.map = Map(stdscr, objects)
        self.msgscr = stdscr  # main messages
        self.sttscr = stdscr  # show status
        self.errscr = stdscr  # show errors
        self.inpscr = stdscr  # get inputs
        self.invscr = stdscr  # inventory overview
        self.itmscr = stdscr  # item description
        for x in range(amountGold):
            self.spawn('Gold')
        for x in range(amountMonster):
            monster = random.choice(enemy_keys)
            self.spawn(monster)
        for x in range(amountWall):
            self.spawn('Wall')
        for x in range(amountFood):
            self.spawn('Food')
        for x in range(amountItem):
            self.spawn('Map item')
        self.current_actor = self.map.objects.lists.get('Hero')[0]

    def __del__(self):
        endwin()

    ########################### drawing ############################

    def all_refresh(self):
        self.map.stdscr.refresh()
        self.msgscr.refresh()
        self.sttscr.refresh()
        self.errscr.refresh()
        self.inpscr.refresh()
        self.invscr.refresh()
        self.itmscr.refresh()

    def all_erase(self):
        self.map.stdscr.erase()
        self.msgscr.erase()
        self.sttscr.erase()
        self.errscr.erase()
        self.inpscr.erase()
        self.invscr.erase()
        self.itmscr.erase()

    def draw(self):
        self.map.draw()
        self.show_stats()

        self.all_refresh()

    def show_stats(self):
        for hero_id in range(0, len(self.map.objects.lists.get('Hero'))):
            hero = self.map.objects.lists.get('Hero')[hero_id]
            if hero.status != 'dead':
                if hero == self.current_actor:
                    self.sttscr.addstr(0, max_x + 5 + 10 * hero_id,
                                       "=" + str(hero.name) + "=")
                else:
                    self.sttscr.addstr(0, max_x + 5 + 10 * hero_id,
                                       " " + str(hero.name))
                self.sttscr.addstr(1, max_x + 5 + 10 * hero_id,
                                   "LV " + str(hero.level))
                self.sttscr.addstr(2, max_x + 5 + 10 * hero_id,
                                   "HP " + str(hero.hp))
                self.sttscr.addstr(3, max_x + 5 + 10 * hero_id,
                                   "XP " + str(hero.xp))
                self.sttscr.addstr(4, max_x + 5 + 10 * hero_id,
                                   "G " + str(hero.gold))
            else:
                self.sttscr.addstr(0, max_x + 5 + 10 * hero_id, " ___")
                self.sttscr.addstr(1, max_x + 5 + 10 * hero_id, "/   \\")
                self.sttscr.addstr(2, max_x + 5 + 10 * hero_id, "|o o|")
                self.sttscr.addstr(3, max_x + 5 + 10 * hero_id, "\\ \" /")
                self.sttscr.addstr(4, max_x + 5 + 10 * hero_id, " |m|")

    def show_level_up(self):
        if self.current_actor.type_name == 'Hero':
            self.all_erase()
            self.map.stdscr.addstr(2, 2, "    _     _")
            self.map.stdscr.addstr(3, 2, "|  |_\\  /|_ |")
            self.map.stdscr.addstr(4, 2, "|_ |_ \\/ |_ |_")
            self.map.stdscr.addstr(5, 6, "     _")
            self.map.stdscr.addstr(6, 6, "| | |_) |")
            self.map.stdscr.addstr(7, 6, ":_: |   o")
            self.map.stdscr.addstr(10, 2, "attack up!")
            self.map.stdscr.addstr(11, 2, "defense up!")
            self.map.stdscr.addstr(12, 2, "max hp up!")
            self.map.stdscr.addstr(15, 2, "Press any key to return")
            self.all_refresh()
            self.map.stdscr.getkey()

    def show_stage_clear(self):
        if self.current_actor.type_name == 'Hero':
            self.all_erase()
            self.msgscr.addstr(2, 2,
                               "Congratulations, you have cleared the stage.")
            self.msgscr.addstr(3, 2, "But your quest is not over.")
            self.msgscr.addstr(15, 2,
                               "Press any key to continue to the next stage.")
            self.all_refresh()
            self.msgscr.getkey()

    def show_message(self, message):
        if self.current_actor.type_name == 'Hero':
            self.msgscr.addstr(max_y + 2, 0, message)

    def show_error(self, message):
        self.errscr.addstr(max_y + 5, 0, message)

    def show_input(self, message):
        self.inpscr.addstr(2, 0, "You've entered: ")
        self.inpscr.addstr(3, 0, message)
        self.inpscr.addstr(4, 0, "Accept? [y/n]")
        key = self.inpscr.getkey()
        if (key == "y"):
            return 1
        if (key == "n"):
            return 0
        return 2

    def prompt_input(self, message):
        self.inpscr.addstr(0, 0, message)
        return self.inpscr.getstr()

    def show_help(self):
        self.map.stdscr.addstr(
            0, 0, """
        1-9 - select actor
        arrows - move
        """ + look_keys + """ - look
        """ + attack_keys + """  - attack
        [S]ave [L]oad [I]nventory
        [q]uit
        any button - Start
        """)

    ########################### interactions ############################

    def spawn(self, object_type):
        """Generator of new objects of any available type"""

        # verify if object limit not reached
        if (self.map.objects.check_limit()):
            self.show_error("Can't create more objects!")
            return

        # roll new coords
        new_x = random.randint(1, max_x)
        new_y = random.randint(1, max_y)

        # verify if coords are valid (no object there)
        # repeat spawn if cords were bad
        if (self.map.objects.check_coords(new_x, new_y)):
            self.spawn(object_type)
            return

        # create object otherwise
        self.map.objects.create_object(object_type, new_x, new_y)

    def pick_up(self):
        """
        pick up an object lying by actor's feet
        :return: 0 - ok. 1 - not item. 2 - inventory full.
        """
        target = self.map.objects.get_object(self.current_actor.x,
                                             self.current_actor.y,
                                             self.current_actor.type_name)

        if not isinstance(target, MapItem):
            return 1

        # Try adding to inventory
        result = self.current_actor.inventory.inventory_add(
            InventoryItem(target.ItemID))
        if (result == 0):
            # Item added
            self.map.objects.remove_object(target)

        return result

    ########################### control ############################

    def game_start(self):
        # show_animation(self.map.stdscr)
        self.show_help()
        # Clean unused keys
        while (self.map.stdscr.getch() in ignore_keys):
            self.map.stdscr.getch()
        self.all_erase()
        self.draw()

    def action_spawn(self, key):
        if (key == 'n' and debug):
            self.show_error(self.map.objects.spawn('Gold'))
            self.show_error(self.map.objects.spawn('Monster'))
            self.show_error(self.map.objects.spawn('Orc'))
            self.show_error(self.map.objects.spawn('Troll'))
            self.show_error(self.map.objects.spawn('Wall'))
            self.show_error(self.map.objects.spawn('Food'))
            self.show_error(self.map.objects.spawn('Map item'))
            return

    def action_pick_up(self, key):
        """result of looking at objects but only if attack button was pressed"""
        if (key == ' '):
            self.pick_up()

    def action_look(self, key):
        """result of looking at objects but only if attack button was pressed"""
        if (key in look_keys):
            self.show_message(self.map.objects.look_at(key,
                                                       self.current_actor))

    def action_attack(self, key):
        """result of attack but only if attack button was pressed"""
        if (key in attack_keys):
            self.show_message(self.map.objects.attack(key, self.current_actor))

    def action_move(self, key):
        """result of moving but only if arrow button was pressed"""
        if (key in move_keys):
            self.show_message(self.map.objects.move(key, self.current_actor))

    def action_inventory(self, key):
        if (key == 'I'):
            self.all_erase()
            dropped_items = self.current_actor.inventory.view(
                self.invscr, self.current_actor)
            if dropped_items is not None:
                for item in dropped_items:
                    self.map.objects.lists.get('Map item').append(
                        MapItem(item, self.current_actor.x,
                                self.current_actor.y))
            self.draw()

    def action_saveload(self, key):
        """
        TODO, nothing is completed here
        :param key: pressed key
        :return: nothing yer
        """
        if (key == 'S'):
            prompt = "Save Game menu. Give savefile name."
            savename = self.prompt_input(prompt)
            result = self.show_input(savename)
            self.inpscr.erase()
            if (result == 0):
                # Return to map
                "?"
            if (result == 1):
                # Check if exists, ask to confirm overwrite
                message = "Game saved!"
                self.show_message(message)
            if (result == 2):
                self.action_saveload(key)

        if (key == 'L'):
            prompt = "Load Game menu. Give savefile name."
            savename = self.prompt_input(prompt)
            result = self.show_input(savename)
            self.inpscr.erase()
            if (result == 0):
                # Return to map
                "?"
            if (result == 1):
                # Check if file exists, raise error otherwise
                message = "Game Loaded!"
                self.show_message(message)
            if (result == 2):
                self.action_saveload(key)

    def check_quit(self, key):
        score = 0
        for hero_id in range(0, len(self.map.objects.lists.get('Hero'))):
            hero = self.map.objects.lists.get('Hero')[hero_id]
            if hero.hp <= 0:
                self.map.objects.remove_object(hero)
            if hero.status != 'dead':
                score += 5 * hero.xp + 4 * hero.gold + 10 * hero.hp - hero.steps

        if score == 0:
            self.all_erase()
            self.show_stats()
            self.map.stdscr.addstr(0, 0, "Try again!")
            self.map.stdscr.addstr(1, 1, "THE END")
            self.all_refresh()
            return False

        enemies_left = self.map.objects.count_enemies()
        if key == 'q':
            self.all_erase()
            self.show_stats()
            self.map.stdscr.addstr(0, 0, "final score: " + str(score))
            self.map.stdscr.addstr(1, 1, "THE END")
            return False
        # level clear and standing on the stairs
        if enemies_left == 0 and self.current_actor.x == max_x and self.current_actor.y == max_y:
            self.show_stage_clear()
            return False
        return True

    def action(self, key):
        """main function in the game
        given input is put to all main actions and results are redrawn,
        afterwards program is ready for another input.
        """

        if (ord(key) in ignore_keys):
            return True

        # force hero switch if current is dead
        if self.current_actor.status == 'dead':
            for hero_id in range(0, len(self.map.objects.lists.get('Hero'))):
                selected_hero = self.map.objects.lists.get('Hero')[hero_id]
                if selected_hero.status != 'dead':
                    self.current_actor = selected_hero
        if self.current_actor.status == 'dead':
            return False

        # user-requested hero switch (only to living one)
        if key in "123456789" and int(key) in range(
                0,
                len(self.map.objects.lists.get('Hero')) + 1):
            selected_hero = self.map.objects.lists.get('Hero')[int(key) - 1]
            if selected_hero.status != 'dead':
                self.current_actor = selected_hero
        bad_tmp = self.current_actor.level

        # check key in every action
        self.all_erase()
        self.action_spawn(key)
        self.action_pick_up(key)
        self.action_look(key)
        self.action_attack(key)
        self.action_move(ord(key))
        self.action_inventory(key)
        self.action_saveload(key)

        # Monster action
        self.map.objects.enemy_action(1)

        if self.current_actor.level > bad_tmp:
            self.show_level_up()
            self.all_erase()

        self.draw()
        self.current_actor.steps += 1

        # Depending on result - continue, game over OR (TODO) next level
        return self.check_quit(key)
Ejemplo n.º 2
0
class Camera(object):
    def __init__(self, screen_size, roster, flags):
        self.screen_size = screen_size
        self.flags = flags
        self.controller = Controller()
        # build team roster
        self.team = []
        for hero in roster:
            self.add_hero(hero_data=hero)

        self.player = self.team[0]

        self.center_box = pygame.Rect(self.screen_size[0] / 4,
                                      self.screen_size[1] / 4,
                                      self.screen_size[0] / 2,
                                      self.screen_size[1] / 2)

        self.cam_center = (self.screen_size[0] / 2, self.screen_size[1] / 2)
        self.cam_offset_x = 0
        self.cam_offset_y = 0
        self.map = None
        self.menu = None
        self.show_menu = False

        self.notification = None

        self.destination_door = None
        self.fade_alpha = 0
        self.fade_speed = 5
        self.fade_out = False
        self.fade_in = False

        self.text_box = self.build_text_box()
        self.blackness = pygame.Surface(self.screen_size)
        self.blackness.fill((0, 0, 0))
        self.blackness.set_alpha(self.fade_alpha)

        # battle
        self.in_battle = False
        self.battle = None

    def build_text_box(self, left=4, top=500, height=200, color=(20, 30, 200)):
        return TextBox(
            pygame.Rect(left, top, self.screen_size[0] - left * 2, height),
            "TEXT", color)

    def convert_door_destination(self, cords):
        x = int(cords[0]) * self.map.tileset_data["t_width"]
        y = int(cords[1]) * self.map.tileset_data["t_height"]
        return x, y

    def load_map(self, map_name, goto=None):
        self.map = Map(camera=self, directory=map_name)
        if goto:
            self.player.teleport(x=goto[0], y=goto[1])
        elif self.map.starting_location:
            self.player.teleport(x=self.map.starting_location[0],
                                 y=self.map.starting_location[1])
        self.cam_offset_x = self.player.sprite_rect.left
        self.cam_offset_y = self.player.sprite_rect.top

    def draw_map(self, screen, draw_player=True):
        view = pygame.Surface(self.map.map_size)
        self.map.draw(view, passmap=False)
        if draw_player:
            self.player.draw(view)
        self.map.draw_upper(view)
        screen.blit(view, (self.cam_center[0] - self.cam_offset_x,
                           self.cam_center[1] - self.cam_offset_y))

    def open_menu(self):
        self.menu = Menu(screen_size=self.screen_size,
                         color=(20, 30, 200),
                         actor_list=self.team)
        self.show_menu = True
        self.menu.open()

    def close_menu(self):
        self.menu.close()
        self.show_menu = False
        self.menu = None

    def add_hero(self, hero_data):
        with open(path.join(settings.ASS_DATA,
                            "ally_specs.json")) as data_file:
            data = json.load(data_file)[hero_data["DATA"]]
            player_battle = BattleObject(
                name=hero_data["NAME"] or data["NAME"],
                sprite_sheet=SpriteSheet(
                    path.join(settings.BATTLE, data["BATTLE"]["SPRITE"]),
                    data["BATTLE"]["WIDTH"], data["BATTLE"]["HEIGHT"]),
                sprite_rect=pygame.Rect(0, 0, data["BATTLE"]["WIDTH"],
                                        data["BATTLE"]["HEIGHT"]),
                team=0,
                stats=hero_data["STATS"] or data["BATTLE"]["BASE_STATS"])
            player_data = {"properties": data}
            player_data["properties"]["SPEED"] = settings.PLAYER_SPEED
            self.team.append(
                Player(actor_json=player_data, battle_object=player_battle))
            data_file.close()

    def start_battle(self, battle_index):
        self.battle = Battle(screen_size=self.screen_size,
                             battle_index=battle_index,
                             team=[self.player])
        self.in_battle = True

    def update(self, screen):
        if self.notification:
            self.notification.draw(screen)
            if self.controller.any_key():
                self.notification = None
        elif self.in_battle:
            if self.battle.state == "END":
                self.in_battle = False
                self.battle = None
            else:
                self.controller.poll_battle(self.battle)
                self.battle.draw(screen)
        elif self.show_menu:
            self.controller.poll_main_menu(camera=self)
            # performance hit might be if you draw this map under the box
            self.draw_map(screen=screen, draw_player=False)
            if self.menu:
                self.menu.draw(screen)
        else:
            if not self.fade_in and not self.fade_out:
                # check for door intersection here?
                for d in self.map.door_list:
                    if d.door.colliderect(self.player.pass_rect):
                        self.destination_door = d
                        self.fade_alpha = 0
                        self.fade_out = True
                if self.player.acting:
                    self.player.move_to()
                else:
                    self.controller.poll(camera=self,
                                         tbox=self.text_box,
                                         action_map=self.map.action_map)
                # check if camera should shift
                if self.player.sprite_rect.left < self.cam_offset_x - self.center_box.left:
                    self.cam_offset_x -= settings.CAM_SPEED
                elif self.player.sprite_rect.left > self.cam_offset_x + self.center_box.left:
                    self.cam_offset_x += settings.CAM_SPEED
                if self.player.sprite_rect.top < self.cam_offset_y - self.center_box.top:
                    self.cam_offset_y -= settings.CAM_SPEED
                elif self.player.sprite_rect.top > self.cam_offset_y + self.center_box.top:
                    self.cam_offset_y += settings.CAM_SPEED

            # update NPC movement
            for actor in self.map.actor_list:
                if actor.behavior == "WANDER":
                    if actor.internal_clock > 1:
                        actor.move_to()
                        actor.internal_clock -= 1
                    else:
                        x = random.randrange(
                            -3, 4) * actor.position.width + actor.position.left
                        y = random.randrange(
                            -3, 4) * actor.position.height + actor.position.top
                        actor.set_destination(x=x, y=y)
                        # print("MOVING ACTOR from {0}, {1} to {2}, {3}".format(actor.position.left,
                        #                                                       actor.position.top, x, y))
                        actor.internal_clock = random.randrange(200, 400)

            # draw things
            self.draw_map(screen=screen)
            screen.blit(self.blackness, (0, 0))
            if self.text_box:
                self.text_box.draw(screen)

            if self.fade_in:
                if self.fade_alpha > 0:
                    self.fade_alpha -= self.fade_speed
                    self.blackness.set_alpha(self.fade_alpha)
                    screen.blit(self.blackness, (0, 0))
                else:
                    self.fade_in = False
            elif self.fade_out:
                if self.fade_alpha < 255:
                    self.fade_alpha += self.fade_speed
                    self.blackness.set_alpha(self.fade_alpha)
                    screen.blit(self.blackness, (0, 0))
                else:
                    self.fade_out = False
                    self.fade_in = True
                    print(self.destination_door.destination_map)
                    self.load_map(
                        map_name=self.destination_door.destination_map)
                    door_cords = self.convert_door_destination(
                        self.destination_door.destination_cords)
                    self.player.teleport(x=door_cords[0], y=door_cords[1])

    def save_game(self):
        save_path = path.join("..", "data", "save.json")
        char_block = {
            "DATA": "BOBMAN",
            "STATS": self.player.battle_object.stats
        }
        loc_block = {
            "MAP": self.map.name,
            "POSITION":
            (self.player.sprite_rect.left, self.player.sprite_rect.top)
        }
        save_block = {
            "CHAR": char_block,
            "LOC": loc_block,
            "FLAGS": self.flags
        }
        with open(save_path, 'w') as out_file:
            json.dump(save_block, out_file)
            out_file.close()
        self.notification = Notice(screen_size=self.screen_size,
                                   text="GAME SAVED",
                                   color=(80, 80, 150))

    def exit(self):
        print("Exiting gracefully...")
        sys.exit(0)