Esempio n. 1
0
class Controller(object):
    """ The controller class - holds the map, instantiates the rooms, tracks the
        player and enemies """
    DIRECTIONS = {
        'EAST': (1, 0),
        'WEST': (-1, 0),
        'SOUTH': (0, -1),
        'NORTH': (0, 1)
    }

    def __init__(self, startCoords=(0, 0)):
        """ Controller constructor
            New game: self._startinPosition = (0, 0)
            Load game: self._startingPosition = startCoords """

        self._saveDir = 'saves'
        self._player = Player("Patrick", 15, gold=100)
        self._playerLocation = startCoords
        self._room = None
        self.map = None
        self._currentRoom = None
        self.loadFile('src/data/world.csv')
        self._roomKey = self.getRoomKey()
        # Preseed _visited dict with special rooms
        self._visited = {
            '00': Room(0, 0, self.map['00'][1]),  # Office
            '01': SearchRoom(0, 1, self.map['01'][1]),  # Search
            '02': TutorialRoom(0, 2, self.map['02'][1]),  # Interrogate
            '03': Room(0, 3, self.map['03'][1]),  # Combat
            '-55': Bookstore(-5, 5, self.map['-55'][1]),  # Bookstore
            '-312': GroceryStore(-3, 12, self.map['-312'][1]),  # Grocery
            '110': Bar(1, 10, self.map['110'][1]),  # Bar
            '615': Room(6, 15, self.map['615'][1])  # Apartment
        }

        self._gameView = GameView(self.getDescriptionText(),
                                  self.getStatText(),
                                  directions=self.getDirectionOptions(),
                                  actions=self.getActionOptions(),
                                  gameOpts=self.getGameOptions(),
                                  controller=self)

        self._initialView = InitialView(['New game', 'Load game', 'Exit'],
                                        self._gameView,
                                        game_loop=None,
                                        controller=self)
        self._loop = MainLoop(self._initialView.screen,
                              palette=[('reversed', 'standout', '')])
        self._initialView.set_game_loop(self._loop)

    def start(self):
        """ Start the main game loop """
        logging.info('Game started')
        self._loop.run()

    def stop(self):
        """ Stop the main game loop """
        self._loop.stop()

    def loadFile(self, mapFile):
        """ReturnType void"""
        self.map = {}

        with open(mapFile) as csvDataFile:
            csvReader = csv.reader(csvDataFile, delimiter='|')
            for row in csvReader:
                key = "{0}{1}".format(row.pop(0), row.pop(0))
                roomTitle = row.pop(0)
                self.map.update({key: [roomTitle, row]})
        logging.debug(str(self.map))

    def getPlayerLocation(self):
        """ Returns the player's current location as a tuple
            ReturnType tuple (x, y) """
        logging.debug('Accessing Controller._playerLocation: %s',
                      self._playerLocation)
        return self._playerLocation

    def getRoomKey(self):
        """ Generates a key for the map based on the player's current location
            @ReturnType String """
        return '{}{}'.format(self._playerLocation[0], self._playerLocation[1])

    def getRooms(self):
        """ Returns the loaded map. It is slated for removal very soon and should
            not be used
            @ReturnType dict """
        return self.map

    def getDescriptionText(self):
        """ Gets the description text from the room at the player's current location

            @ReturnType String """
        text = self._visited[self._roomKey].getText()
        return text

    def getStatText(self):
        """ Returns a formatted string representation of the player's basic stats,
            including current health / max health, equipped weapon, and damage range """
        stats = "HP: {}/{}         Equipped weapon: {}        Damage: {}".format(
            self._player.getHP(), self._player.getMaxHP(),
            self._player._weapon._name, self._player._weapon.getDamage())
        return stats

    def _canMove(self, direction):
        """ Checks if there is a room in <direction> from current room """
        dirX, dirY = Controller.DIRECTIONS[direction]
        roomKey = '{}{}'.format(self._playerLocation[0] + dirX,
                                self._playerLocation[1] + dirY)
        return roomKey in self.map

    def getDirectionOptions(self):
        """ Builds the list of directions the player can move
            ReturnType list of Strings """
        return [
            "Move {}".format(x).title()
            for x in ["NORTH", "WEST", "EAST", "SOUTH"] if self._canMove(x)
        ]

    def getActionOptions(self):
        """ Builds and returns the list of actions the player can take in the room
            ReturnType list of Strings """
        options = []
        # Try to add item to menu
        try:
            if not self._room.item.isHidden():
                logging.debug("Visible item in room")
                options.append("Pick up " + self._room.item.identify())
            else:
                logging.debug("Hidden item in room")
                options.append("Search room")
        except AttributeError:
            logging.debug("No item in room")
            pass
        # Try to add enemy to menu
        try:
            if not self._room.enemy.isDead():
                options.append("Fight " + self._room.enemy.getName())
        except AttributeError:
            pass
        # Try to add NPC to menu
        try:
            options.append("Interrogate " + self._room.character.getName())
        except AttributeError:
            pass

        return options

    def getGameOptions(self):
        """ Returns the metagame options (e.g. Save, Load, Quit)
            ReturnType list of strings """
        options = ["Save", "Load", "Exit game"]
        return options

    def movePlayer(self, direction):
        """ Updates the player's current location and instantiates a room if necessary
            ReturnType None """
        if not self._canMove(direction):
            return
        self._player.move(Controller.DIRECTIONS[direction])
        self._playerLocation = self._player.getLocation()
        self._roomKey = self.getRoomKey()
        try:
            logging.debug('Returning to previously visited room')
            self._room = self._visited[self._roomKey]
        except KeyError:
            logging.debug('Visiting a new room, generating room')
            self._visited[self._roomKey] = Factory.roomFactory(
                self._playerLocation[0], self._playerLocation[1],
                self.map[self._roomKey][1])
            self._room = self._visited[self._roomKey]
            logging.debug('Created new room')
        finally:
            logging.debug('Room %s', self._roomKey)
            logging.debug('Room description: %s', self._room.getText())

    def updateGameView(self):
        """ Updates the GameView screen after player action """

        self._gameView.updateDescription(self.getDescriptionText())
        self._gameView.updateStats(self.getStatText())
        self._gameView.updateDirectionMenu(self.getDirectionOptions())
        self._gameView.updateActionMenu(self.getActionOptions())
        self._gameView.setMenuFocus(0)

    def moveCallback(self, button):
        """ Updates the gameView object every time the player moves """
        functions = {
            'move_north': (self.movePlayer, "NORTH"),
            'move_south': (self.movePlayer, "SOUTH"),
            'move_east': (self.movePlayer, "EAST"),
            'move_west': (self.movePlayer, "WEST")
        }
        label = button._w.original_widget.text.lower().replace(' ', '_')
        try:
            functions[label][0](functions[label][1])
        except KeyError:
            return
        self.updateGameView()

    def optionCallback(self, button):
        """ Updates the gameView object whenever the player uses the
            game options menu (save/load/quit/etc) """
        functions = {
            'save': self.saveGame,
            'load': self.loadGame,
            'exit_game': exitGame
        }
        label = button._w.original_widget.text.lower().replace(' ', '_')
        try:
            functions[label]()
        except KeyError:
            pass

    def actionCallback(self, button):
        """ Updates the gameView object whenever the player performs an action from
            the action menu
            Precondition: Action menu item is selected by player. Action menu items should be in
                          the format 'pick up <item>', 'fight <enemy>', 'interrogate <npc>'
            Postcondition: The appropriate action method is run
            @ReturnType None"""
        label = button._w.original_widget.text.lower().replace(' ', '_')
        try:
            if self._room.item.isHidden():
                logging.debug("Trying to search the room")
                if self._room.search():
                    logging.debug("Found item %s", self._room.item.identify())
                    self._room.item.find()
                    self._room.updateText(
                        "You're in the hallway outside your office. \
This is where you found the {}.".format(self._room.item.identify()))
                else:
                    logging.debug("Item still hidden")
            else:
                logging.debug("Trying to add item to inventory")
                logging.debug(self._room.item)
                self._player.addItem(self._room.item)
                self._room.removeItem()
        except AttributeError:
            logging.debug("No item in room")
            try:
                logging.debug("Trying to fight enemy")
                self._player.fight(self._room.enemy)
                logging.debug(
                    "Fought enemy - results: Player HP: %s\nEnemy HP: %s",
                    self._player.getHP(), self._room.enemy.getHP())
                if self._room.enemy.isDead():
                    self._room.killEnemy()
                else:
                    self.playerDead()
            except AttributeError:
                logging.debug("No enemy to fight")
                self._player.interrogate(self._room.character)
        finally:
            self.updateGameView()
            logging.debug("Action menu item %s pressed", label)

    def playerDead(self):
        """ Handle the player dying """
        pass

    def saveGame(self):
        """ Pickles the controller state and player to save the current game state
            Precondition: None
            Postcondition: Saves game state in saves/<player name>_<save index>
            @ReturnType None """
        try:
            makedirs(self._saveDir)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
        with open(self._saveDir + '/patrick_001', 'w+') as f:
            dill.dump(self._player, f)
            dill.dump(self._playerLocation, f)
            dill.dump(self._currentRoom, f)
            dill.dump(self.map, f)
            dill.dump(self._visited, f)
            dill.dump(self._roomKey, f)

    def loadGame(self):
        """ Unpickles the controller (self) and player (self._player) to load the
            saved game state
            Precondition: Save game file in saves/<player name>_<save index>
            Postcondition: Loads game state
            @ReturnType None """
        try:
            with open(self._saveDir + '/patrick_001') as f:
                self._player = dill.load(f)
                self._playerLocation = dill.load(f)
                self._currentRoom = dill.load(f)
                self.map = dill.load(f)
                self._visited = dill.load(f)
                self._roomKey = dill.load(f)
                self.updateGameView()
        except IOError:
            return
Esempio n. 2
0
import unittest
from src.player import Player
from src.enemy import *
from src.weapon import Weapon
from src.consumable import *

e = Enemy("Brownie", 10, 2, ET.BROWNIE)
p = Player("sword gumby", 25, weapon=Weapon(5, "neat shiny sword"))
c = Consumable.create()
p.addItem(c)


def test_player_instantiate():
    assert (p.getName() == "sword gumby" and p.getHP() == 25)


def test_player_damage():
    p.takeDamage(5)
    assert p.getHP() == 20


def test_player_heal():
    p.heal(3)
    assert p.getHP() == 23


def test_player_name_change():
    newName = "angry sword gumby"
    p.setName(newName)
    assert p.getName() == newName