Exemple #1
0
    def bless(self):
        player = self.get_current_player()
        old_aura = player.hex.aura
        n_actions = self.current_board.actions

        if old_aura == self.current_board.faction:
            raise InvalidMove(
                'You cannot bless a hex that already has your aura')
        elif old_aura == None:
            if n_actions < 1:
                raise InvalidMove(
                    'You cannot bless because you have no more actions')
            self.current_board.actions -= 1
            player.hex.aura = self.current_board.faction
        else:
            if n_actions < 2:
                raise InvalidMove(
                    'You cannot bless because you have {} action{} remaining'.
                    format(
                        n_actions,
                        '' if n_actions == 1 else 's',
                    ))
            self.current_board.actions -= 2
            player.hex.aura = self.current_board.faction
        return True
Exemple #2
0
 def _validate_artwork_status(self, board):
     # if the spell has an artwork, check if it's placed on the board, on your aura
     if self.artwork:
         if self.artwork.hex:
             if self.artwork.hex.aura != board.faction:
                 raise InvalidMove('{} artwork is not on player\'s aura'.format(self.name))
         else:
             raise InvalidMove('{} artwork is not placed on board'.format(self.name))
Exemple #3
0
    def drop(self):
        if self.current_board.actions < 1:
            raise InvalidMove(
                'You cannot drop because you have no more actions')

        # get list of eligible hexes
        player = self.get_current_player()
        adj_hexes = find_adjacent_hexes(self.current_board, player.hex)
        adj_hexes_wo_objs = [h for h in adj_hexes if h.occupant == None]
        if len(adj_hexes_wo_objs) == 0:
            raise InvalidMove('There is no adjacent hex where you can drop')

        # get list of eligible artworks
        faction = self.current_board.faction
        eligible_artworks = []
        for artwork in self.current_board.artworks:
            if artwork.faction == faction and artwork.hex == None:
                eligible_artworks.append(artwork)
        if len(eligible_artworks) == 0:
            raise InvalidMove(
                '{} does not have any unplaced artworks'.format(faction))

        artwork = self.screen.choice(0)
        if artwork == None:
            # set artwork based on click if it's been chosen
            if 'click_spell_idx' in self.screen.data:
                spell_idx = self.screen.data['click_spell_idx']
                click_artwork = self.current_board.spells[spell_idx].artwork
                self.screen.data.pop('click_spell_idx')
                if click_artwork in eligible_artworks:
                    artwork = click_artwork
                    self.screen.choices.append(artwork)

            # otherwise, get user input
            else:
                artwork = self.screen_input.choose_from_list(
                    self.screen, eligible_artworks, 'Choose artwork to drop:',
                    '{} does not have any unplaced artworks'.format(faction))
        if artwork == None:
            return False

        # prompt for hex choice if needed
        hex = self.screen_input.choose_hexes(
            self.screen,
            adj_hexes_wo_objs,
            'Click where to drop {}'.format(artwork),
            'There is no adjacent hex where you can drop',
        )
        if hex == None:
            return False

        self.current_board.actions -= 1
        self.current_board.move_object(artwork, to_hex=hex)
        return True
Exemple #4
0
    def pick_up(self):
        if self.current_board.actions < 1:
            raise InvalidMove(
                'You cannot pick up because you have no more actions')

        # get list of eligible hexes
        player = self.get_current_player()
        adj_hexes = find_adjacent_hexes(self.current_board, player.hex)

        # get list of eligible artworks
        faction = self.current_board.faction
        eligible_artworks = []
        coords = []  # coordinates of eligible_artworks
        for artwork in self.current_board.artworks:
            if artwork.faction == faction and artwork.hex in adj_hexes:
                eligible_artworks.append(artwork)
                coords.append(artwork.hex)

        # prompt for artwork choice if needed
        artwork_idx = self.screen_input.choose_hexes(
            self.screen,
            coords,
            'Click artwork to pick up',
            '{} does not have any adjacent artworks to pick up'.format(
                faction),
            return_index=True,
        )
        if artwork_idx == None:
            return False

        artwork = eligible_artworks[artwork_idx]

        self.current_board.actions -= 1
        self.current_board.move_object(artwork, from_hex=artwork.hex)
        return True
Exemple #5
0
def choose_from_list(screen,
                     ls,
                     prompt_text='Choose one:',
                     error_text='No valid choices',
                     all_spells=None):
    if len(ls) == 0:
        raise InvalidMove(error_text)
    elif len(ls) == 1:
        return ls[0]

    prompt = prompt_text
    for idx, obj in enumerate(ls, start=1):
        prompt += ' ({}) {}'.format(idx, obj)

    screen.info.text = prompt
    screen.toggle_action_buttons()
    while True:
        choice = get_keypress(screen)
        try:
            ret = ls[int(choice) - 1]
            screen.toggle_action_buttons()
            screen.info.error = None
            return ret
        except (ValueError, IndexError):
            screen.info.error = 'Please enter a number 1-{}'.format(len(ls))
Exemple #6
0
    def cast(self, board):
        self._validate_spell_status_and_tap(board)
        # get list of linked objects
        linked_hexes = location.linked_hexes(board, self.artwork.hex)
        linked_objects = [hex.occupant for hex in linked_hexes if hex.occupant]

        # get list of hexes to move to from the board
        target_hexes = [hex for hex in board.get_all_hexes() if not(hex.occupant)]
        if target_hexes == []:
            # this cannot happen since there are only 9 possible occupants :)
            raise InvalidMove('All hexes are occupied.')

        # choose a linked object to move. There should always be at least one,
        # since we've validated that the Locksmith is on an aura
        target_object = board.screen.choice(1) or choose_from_list(
            board.screen,
            linked_objects,
            prompt_text='Choose object to move:',
        )
        if target_object == None:
            return self._exit_cast(done=False)

        target_hex = choose_hexes(
            board.screen,
            target_hexes,
            prompt_text='Click where to move {}'.format(target_object)
        )
        if target_hex == None:
            return self._exit_cast(done=False)

        board.move_object(target_object, from_hex = target_object.hex, to_hex = target_hex)
        return self._exit_cast(done=True)
Exemple #7
0
    def _validate_spell_status_and_tap(self, board):
        # current player must own spell
        if self.faction != board.faction:
            raise InvalidMove("{} cannot cast {} because it is owned by {}".format(
                board.faction,
                self.name,
                self.faction,
            ))

        # spell cannot already have been used
        if self.tapped:
            raise InvalidMove("{} already cast".format(self.name))

        # artwork must also have correct status
        self._validate_artwork_status(board)

        # mark spell used
        self.tapped = True
Exemple #8
0
 def move_object(self, occupant, from_hex=None, to_hex=None):
     # order matters here, updating occupant.hex last makes it ok for
     # from_hex to be occupant.hex initially
     if from_hex != None:
         from_hex.set_object(None)
     if to_hex != None:
         if to_hex.occupant != None:
             raise InvalidMove('You\'re trying to move onto an occupied hex.')
         to_hex.set_object(occupant)
     occupant.hex = to_hex
Exemple #9
0
    def set_object(self, occupant):
        # validate occupant type
        try:
            if occupant != None:
                occupant.get_obj_type(
                )  # only objects (artworks and players) have this method
        except AttributeError:
            raise InvalidMove('TypeError placing {}'.format(self, occupant))

        self.occupant = occupant
Exemple #10
0
    def end_turn(self):
        if self.current_board.actions < 0:
            raise InvalidMove(
                'You cannot end turn with negative actions, please reset turn and try again'
            )

        if self.maybe_claim_spell():
            self.current_board.end_turn(
            )  # update faction, untap spells, reset # actions
            self.sync_boards()
            return True
        else:
            return False
Exemple #11
0
    def cast(self, board):
        self._validate_spell_status_and_tap(board)

        # temp room represents all the places that the shovel can be placed
        temp_is_placed = any([room.name == "Temp" for room in board.rooms])
        shovel_room = next((room for room in board.rooms if room.name == "Shovel"), None)
        if not temp_is_placed:
            player_on_shovel = board.get_current_player().hex.room == shovel_room

            if player_on_shovel:
                # shovel can move anywhere - get neighbors of the whole board
                temp_locations = location.find_unoccupied_neighbors(board, board.get_all_hexes())
            else:
                # shovel can move to adjacent spots that are empty - get player's neighbors
                player_hex = board.get_current_player().hex
                temp_locations = location.find_unoccupied_neighbors(board,[player_hex])
                if temp_locations == []:
                    raise InvalidMove("There's nowhere to place the Shovel")

            # make a temporary room with these locations
            board.rooms.append(Room(
                name = "Temp",
                root = None,
                shape = temp_locations,
                a_spell = None,
                b_spell = None,
                relative_shape = False,
            ))

        # get the (possibly first-ever) location for the Shovel
        board.flush_hex_data()
        shovel_hex = choose_hexes(
            board.screen,
            board.rooms[-1].hexes,
            prompt_text = "Choose where the Shovel will go"
        )
        if shovel_hex == None:
            return self._exit_cast(done=False)
        shovel_location = shovel_hex.location

        # get rid of the temporary room
        board.rooms.pop()
        if shovel_room:
            shovel_room.hexes[0].location = shovel_location
        else:
            board.rooms.append(self.create_Shovel_room(shovel_location))

        board.flush_hex_data()
        return self._exit_cast(done=True)
Exemple #12
0
    def move(self):
        if self.current_board.actions < 1:
            raise InvalidMove(
                'You cannot move because you have no more actions')

        player = self.get_current_player()
        adj_hexes = find_adjacent_hexes(self.current_board, player.hex)
        adj_hexes_wo_objs = [h for h in adj_hexes if h.occupant == None]

        hex = self.screen_input.choose_hexes(
            self.screen,
            adj_hexes_wo_objs,
            'Click hex to move to',
            'There is no adjacent hex for you to move',
        )
        if hex == None:
            return False

        self.current_board.actions -= 1
        self.current_board.move_object(player, from_hex=player.hex, to_hex=hex)
        return True
Exemple #13
0
def choose_location(screen,
                    axial_pos,
                    prompt_text="Click a location",
                    error_text="No valid locations"):
    if len(axial_pos) == 0:
        raise InvalidMove(error_text)
    elif len(axial_pos) == 1:
        return 0

    # set prompt
    screen.info.text = prompt_text
    screen.toggle_action_buttons()
    while True:
        pos = get_click(screen)
        if pos in axial_pos:
            ret = axial_pos.index(pos)
            screen.info.error = None
            screen.toggle_action_buttons()
            return ret
        else:
            screen.info.error = 'Please click one of: {}'.format(' '.join(
                map(str, axial_pos)))
Exemple #14
0
def choose_from_list(screen,
                     ls,
                     prompt_text='Choose one:',
                     error_text='No valid choices',
                     all_spells=None):
    if len(ls) == 0:
        raise InvalidMove(error_text)
    elif len(ls) == 1:
        return complete_choice(screen, ls[0])

    if 'choice_idx' in screen.data:
        choice = screen.data['choice_idx']
        screen.data.pop('choice_idx')
        try:
            ret = ls[int(choice) - 1]
            return complete_choice(screen, ret)
        except (ValueError, IndexError):
            screen.info.error = 'Please enter a number 1-{}'.format(len(ls))
            return None
    elif 'click_spell_idx' in screen.data and all_spells:
        # This is a bit hacky, but will work for now
        # This depends on the order of board.spells matching the order on the frontend
        spell = all_spells[screen.data['click_spell_idx']]
        screen.data.pop('click_spell_idx')
        if spell not in ls:
            screen.info.error = 'Cannot cast {}'.format(spell)
            return None

        return complete_choice(screen, spell)
    else:
        prompt = prompt_text
        for idx, obj in enumerate(ls, start=1):
            prompt += ' ({}) {}'.format(idx, obj)

        screen.info.text = prompt
        screen.action_buttons_on = False
Exemple #15
0
def choose_hexes(screen,
                 hex_list,
                 prompt_text="Choose a hex:",
                 error_text="No valid hexes",
                 return_index=False):
    if len(hex_list) == 0:
        raise InvalidMove(error_text)
    elif len(hex_list) == 1:
        if return_index:
            return complete_choice(screen, 0)
        else:
            return complete_choice(screen, hex_list[0])

    # get a list of axial coordinates for the hexes
    screen.active_hexes = hex_list
    axial_coordinates = [location_to_axial(x.location) for x in hex_list]
    chosen_index = location_helper(screen, axial_coordinates, prompt_text)

    if return_index:
        return complete_choice(screen, chosen_index)
    elif chosen_index != None:
        return complete_choice(screen, hex_list[chosen_index])
    else:
        return None  # just being explicit
Exemple #16
0
    def cast_spell(self):
        eligible_spells = self.current_board.get_eligible_spells()

        # TODO[idea]: consider also allowing clicking on artwork to choose spell
        spell = self.screen.choice(0) or self.screen_input.choose_from_list(
            self.screen,
            eligible_spells,
            'Choose spell to cast:',
            '{} does any spells that can be cast'.format(
                self.current_board.faction),
            all_spells=self.current_board.spells)
        if spell == None:
            return False

        try:
            done = spell.cast(self.current_board)
        except InvalidMove as error:
            spell.untap()  # mark spell untapped since it did not complete
            raise InvalidMove(str(error))
            # TODO: make sure no spells raise after mutating game state
            # TODO[idea]: store a 3rd version of board to reset action and use
            # that here

        return done