Exemplo n.º 1
0
 def turn(self):
     creature = self.creature_list[self.index]
     if len(self._moveable_list) == 1:
         self.game_over()
     self.info_pane = InfoPane(self.interface._root, self.interface.canvas, self, self.player)
     self.end_turn_boolean = True
     # creature.prepare_attack = False
     self.current_turn = creature.name
     if creature.hunger_points == 0:
         print("The human is starving.")
     print(creature.name + " attempts to perceive.")
     self.notify_perception_observers(self, creature)
     while self.end_turn_boolean:
         if creature.action_count <= 0:
             self.info_pane.end_turn()
         elif creature.creature_type is "human":
             self.interface.canvas.wait_variable(creature.end_turn)
         elif creature.current_state.name is not "dead":
             self.creature_action(creature)
Exemplo n.º 2
0
class GameWorld(Observer, Observable, Visitable):

    def __init__(self):
        super(GameWorld, self).__init__()
        self._rounds = 1
        self._moveable_list = list()
        self._immovable_list = list()
        self._text_object_list = list()
        self._drawable = list()
        self._creature_list = list()
        self._player = None
        self._interface = None
        self.index = 0
        self.image_state = 0
        self.name = "game world"
        self._current_turn = ""
        self.start = False
        self.end_turn_boolean = True
        self.dark = False
        self.tk_end_turn_boolean = tk.BooleanVar
        self.distance = Distance()
        
        # Visitors
        self.attack_move_position_visitor = AttackMovePositionVisitor()
        self.move_position_visitor = MovePositionVisitor()
        
        # Move Position States
        self._attack_move_position = AttackMovePosition()
        self._move_position = MovePosition()
        self._move_position_state = None

    def accept_visitor(self, visitor):
        visitor.visit(self)

    def find_move_position(self, creature, end_goal):
        return self.move_position_state.find_move_position(creature, end_goal)

    @property
    def attack_move_position(self):
        return self._attack_move_position

    @property
    def move_position(self):
        return self._move_position

    @property
    def move_position_state(self):
        return self._move_position_state

    @move_position_state.setter
    def move_position_state(self, state):
        self._move_position_state = state

    @property
    def current_turn(self):
        return self._current_turn

    @current_turn.setter
    def current_turn(self, current_turn):
        self._current_turn = current_turn

    @property
    def creature_list(self):
        return self._creature_list

    @creature_list.setter
    def creature_list(self, creature_list):
        self._creature_list = creature_list

    @property
    def player(self):
        return self._player

    @player.setter
    def player(self, player):
        assert player in self._moveable_list
        self._player = player

    @property
    def interface(self):
        return self._interface

    @interface.setter
    def interface(self, game_canvas):
        assert self._interface is None
        self._interface = game_canvas

    @property
    def rounds(self):
        return self._rounds

    @rounds.setter
    def rounds(self, value):
        self._rounds = value

    def game_over(self):  # TODO Check if this works.
        if self._moveable_list[0].creature_type is "human":
            print("You are the only creature left alive.")
        else:
            print("You died.")
        print("Game over.")
        exit()

    def start_day(self, start_menu):
        start_menu.destroy()
        day_count = 1
        self.day(day_count)

    def day(self, day_count):
        self.creature_list.sort(key=lambda x: x.initiative_check())
        # TODO Remove creatures from list when they die, not just remove from observers?
        print("The sun comes up.")
        self.dark = False
        print("Day " + str(day_count))
        print("Turn Order:")
        for creature in self.creature_list:
            print(creature.name)
        self.round()
        day_count += 1
        self.day(day_count)

    def round(self):
        print("")
        print("Round " + str(self.rounds))
        if self.rounds > 25:
            self.dark = True
            print("")
            print("The sun goes down.")
            exit()
        self.turn()

    def turn(self):
        creature = self.creature_list[self.index]
        if len(self._moveable_list) == 1:
            self.game_over()
        self.info_pane = InfoPane(self.interface._root, self.interface.canvas, self, self.player)
        self.end_turn_boolean = True
        # creature.prepare_attack = False
        self.current_turn = creature.name
        if creature.hunger_points == 0:
            print("The human is starving.")
        print(creature.name + " attempts to perceive.")
        self.notify_perception_observers(self, creature)
        while self.end_turn_boolean:
            if creature.action_count <= 0:
                self.info_pane.end_turn()
            elif creature.creature_type is "human":
                self.interface.canvas.wait_variable(creature.end_turn)
            elif creature.current_state.name is not "dead":
                self.creature_action(creature)

    def end_turn(self, info_pane):
        info_pane.destroy()
        self.end_turn_boolean = False
        if self.index < (len(self.creature_list) - 1):
            self.index += 1
            self.turn()
        else:
            self.index = 0
            for creature in self.creature_list:
                if (creature.current_state.name == "unconscious and dying" or
                        creature.current_state.name == "unconscious, but stable" or
                        creature.current_state.name == "dead"):
                    creature.action_count = 0
                    creature.standard_action = 0
                    creature.move = 0
                if creature.current_state.name == "staggered":
                    creature.action_count = 1
                    creature.standard_action = 1
                    creature.move_action = 1
                else:
                    creature.action_count = 2
                    creature.standard_action = 1
                    creature.move_action = 2
            self.rounds += 1
            self.round()

    def creature_action(self, creature):
        """Creature Action

        Determines a type of action for the creature. A location is sent to the action method.
        Called by the turn method when on a non-human turn.

        Args:
            creature: the acting creature

        """
        # TODO Sneak is broken.
        # if creature.move.name is not "sneak":
            # creature.set_move(Sneak())
        # self.notify_stealth_observers(self, creature)

        if creature.creature_type is "wolf":
            if creature.standard_action > 0:
                creature.notify_attack_range_observers(creature)
            if creature.prepare_attack and creature.standard_action > 0:
                end = [creature.target.position_col, creature.target.position_row]
                self.action(creature, end)
            elif creature.prepare_attack and creature.standard_action <= 0:
                creature.action_count = 0
            else:
                creature.notify_attack_move_observers(creature)
                if creature.prepare_attack_move:
                    creature.prepare_attack_move = False
                    end_goal = [creature.target.position_col, creature.target.position_row]
                    self.accept_visitor(self.attack_move_position_visitor)
                    end = self.find_move_position(creature, end_goal)
                else:
                    start = [2024, 384]
                    if creature.position == start:
                        end = [creature.position_col - (creature.speed * 64), creature.position_row]
                    else:
                        self.accept_visitor(self.move_position_visitor)
                        end = self.find_move_position(creature, start)
                self.action(creature, end)
        else:
            # TODO Add deer action.
            creature.action_count -= 2
        self.redraw()

    def player_action(self, event):
        """Player Action

        Takes an event and turns it into a location.
        Called by the interface when the user clicks the screen.

        Args:
            event: a click event

        """
        event_col = int(self.interface.canvas.canvasx(event.x))
        event_row = int(self.interface.canvas.canvasy(event.y))
        end = [event_col, event_row]
        self.action(self.player, end)

    def action(self, creature, end):
        """Action

        Decides whether the action is a move or an attack and calls the right method.
        Both creature_action and player_action call action after a location is determined.

        Args:
            creature: the acting creature
            end: the end location for either an attack, a movement, or some other interaction

        """
        interval = 64
        move_distance = creature.speed * interval
        start = [creature.position_col, creature.position_row]
        distance = int(self.distance.compute(start, end))
        if creature.action_count > 0:
            if distance <= move_distance:
                creature.possible_move = end
                creature.prepare_move = True

            creature.notify_move_observers(creature)

            # TODO Add location interaction check
            # It should also be impossible to move through a location, instead it needs to find the best path
            # around the object.

            if creature.prepare_attack and creature.standard_action > 0:
                creature.possible_move_col = creature.position_col
                creature.possible_move_row = creature.position_row
                creature.prepare_move = False
                col = creature.position_col
                row = creature.position_row
                possible_col = creature.possible_move_col
                possible_row = creature.possible_move_row
                if (possible_col in range(int(col) - interval, int(col) + interval) and
                        possible_row in range(int(row) - interval, int(row) + interval)):
                    creature.execute_attack(creature, creature.target, self)
                    self.interface.action_text(creature)
                creature.prepare_attack = False
            elif creature.prepare_move:
                creature.execute_move(creature)
                self.move(creature)
                creature.prepare_move = False

    def move(self, creature):
        """Move

        Gradually moves changes a creatures location. Changes the human player's image for every step.
        Called by action.

        Args:
            creature: the acting creature

        """
        col_num = 4
        row_num = 4
        while (creature.possible_move_col != creature.position_col or
               creature.possible_move_row != creature.position_row):
            if creature.prepare_move:
                if creature.possible_move_col < creature.position_col:
                    creature.position_col += -col_num
                if creature.possible_move_col > creature.position_col:
                    creature.position_col += +col_num
                if creature.possible_move_row < creature.position_row:
                    creature.position_row += -row_num
                if creature.possible_move_row > creature.position_row:
                    creature.position_row += +row_num
                if self.image_state < 4 and creature.creature_type == "human":
                    # TODO This is happening too quickly
                    self.image_state += 1
                    if self.image_state == 4:
                        self.image_state = 0
                    creature.set_image_state(creature.image_list[self.image_state])
                creature.position = [creature.position_col, creature.position_row]
                if self.distance.compute(creature.possible_move, creature.position) < 4:
                    col_num = 1
                    row_num = 1
                self.redraw()
        self.image_state = 0
        if creature.creature_type == "human":
            creature.set_image_state(creature.image_list[self.image_state])
            self.redraw()

    def hide(self, creature):
        self._unregister_drawable(creature)
        self.redraw()

    def perceive(self, creature):
        self._register_drawable(creature)

    def death(self, creature):
        self._creature_list.remove(creature)

    def add_text_object(self, new_object):
        self._text_object_list.append(new_object)

    def remove_text_object(self, new_object):
        self._text_object_list.remove(new_object)

    def add_stationary_world_object(self, new_object):
        self._immovable_list.append(new_object)
        new_object.add_observer(self)
        self.add_observer(new_object)
        if isinstance(new_object, GameDrawable):
            self._drawable.append(new_object)

    def add_world_object(self, new_object):
        self._moveable_list.append(new_object)
        new_object.add_observer(self)
        self.add_observer(new_object)
        if isinstance(new_object, GameDrawable):
            self._register_drawable(new_object)

    def remove_world_object(self, old_object):
        if old_object in self._moveable_list:
            self._moveable_list.remove(old_object)
            old_object.remove_observer(self)
            self.remove_observer(old_object)
        if old_object in self._immovable_list:
            self._immovable_list.remove(old_object)
        if old_object in self._drawable:
            self._unregister_drawable(old_object)
        self.redraw()

    def _register_drawable(self, obj):
        assert isinstance(obj, GameDrawable)
        assert obj not in self._drawable
        self._drawable.append(obj)
        self.redraw()

    def _unregister_drawable(self, obj):
        assert isinstance(obj, GameDrawable)
        assert obj in self._drawable
        self._drawable.remove(obj)

    def redraw(self):
        self.interface.redraw(self._drawable)

    def move_update(self, player):
        self.notify_move_observers(player)

    def attack_range_update(self, creature):
        self.notify_attack_range_observers(creature)

    def attack_move_update(self, creature):
        self.notify_attack_move_observers(creature)

    def change_move(self, key_press):
        self.player.change_move(key_press)