Esempio n. 1
0
    def delete_selected_text(self):
        if (self.selection_start != self.selection_end and
                self.text):
            console_msg("Deleting selection", 8, line_end='')
            # make sure the selection start is the top left of the block
            start_pos = (self.selection_start[Y] * self.row_width
                         + self.selection_start[X])
            end_pos = (self.selection_end[Y] * self.row_width
                       + self.selection_end[X])
            if start_pos > end_pos:
                temp = self.selection_start
                self.selection_start = self.selection_end
                self.selection_end = temp

            self.save_history()
            # prevent backspace() from also trying to delete the block
            self.deleting_block = True
            # make sure the cursor is positioned at the end of the selection
            self.cursor_col, self.cursor_line = self.selection_end
            # backspace all the way to the first char in the selection
            while (self.cursor_col, self.cursor_line) != self.selection_start:
                # turn off undo for the individual deletions,
                # since we have already saved
                self.backspace(undo=False)
                print(".", end='')
            # cancel this selection
            self.selection_start = (0, 0)
            self.selection_end = (0, 0)
            self.deleting_block = False
            print(" done.")
Esempio n. 2
0
 def rewind_level(self):
     console_msg("Rewinding!", 8)
     self.rewinding = True
     self.blocks.reset()
     self.player.set_position(self.blocks.get_player_start(self.puzzle))
     self.dog.set_position(self.blocks.get_dog_start(self.puzzle))
     self.dog.clear_speech_bubble()
Esempio n. 3
0
 def check(self, character):
     """ check if the trigger has activated
     for now this just handles the pressure plate type of trigger
     others will be added - possibly by subclassing this
     """
     if self.type == 'pressure plate':
         trigger_rect = pygame.Rect(self.block.x, self.block.y, BLOCK_SIZE,
                                    BLOCK_SIZE)
         if character.location.colliderect(trigger_rect):
             # switch to 'pressed' state
             self.block.image = self.block.frames[1]
             if self.random:
                 if not self.random_action[0].activated:
                     self.random_action[0].activate(self.random_action[1])
             else:
                 # fire all actions associated with this trigger
                 for action in self.actions:
                     if not action[0].activated:
                         # the action is a tuple of mover and movement
                         # so we call the activate method of the mover
                         # and pass the movement as the argument
                         action[0].activate(action[1])
             console_msg(
                 "trigger " + "(" + str(self.block.x) + str(self.block.y) +
                 ")" + " activated!", 8)
Esempio n. 4
0
 def input(self, msg=''):
     # get input from the user in a separate editor window
     self.world.input.activate('input:' + msg)
     while self.world.input.is_active():
         self.world.update(self)
     result = self.world.input.convert_to_lines()[0]
     console_msg("input:" + str(result), 8)
     return result
Esempio n. 5
0
    def __init__(self, screen, height, code_font):
        self.code_font = code_font
        self.screen = screen
        self.width = screen.get_size()[X]
        self.height = height
        self.surface = pygame.Surface((self.width, self.height))
        self.side_gutter = 8  # pixel gap from the edge of the surface
        self.color_modes = {0: (LIGHT_GREY, SKY_BLUE),
                            1: (BLACK, YELLOW),
                            2: (BLACK, GREEN)}
        self.palette = 0
        self.line_height = self.code_font.get_linesize()
        self.top_margin = self.line_height + 4
        # maximum number of lines that will fit in the editor window
        self.max_lines = int(self.height / self.line_height)
        # width of a single character
        # (monospaced font, so they're all the same)
        self.char_width = self.code_font.size(" ")[X]
        # the margin allows space for the line numbers in the code editor
        self.left_margin = self.side_gutter
        # calculate the number of characters that fit on a line
        self.row_width = int((self.width - self.left_margin - self.side_gutter)
                             / self.char_width)
        self.buttons = button_tray.ButtonTray(EDITOR_ICON_FILE, self.surface)
        self.title = "Title"
        self.centre_title = False  # set to true for the menu input dialog
        # the text is represented as a list of logical lines
        # each line is a list of characters
        # there are no line terminator characters or padding characters
        # we initialise with a single row
        self.text = [[]]
        # undo history is a list where each element is a copy of self.text
        self.history = []
        # absolute line number of the cursor
        self.cursor_line = 0
        # character position of the cursor within the current line
        self.cursor_col = 0
        self.selecting = False  # True when currently marking a block of text
        # cursor coords of the start and end of the marked block
        self.selection_start = (0, 0)
        self.selection_end = (0, 0)
        self.deleting_block = False
        self.v_scroll = 0  # line offset to allow text to be scrolled
        self.active = False
        self.run_enabled = False
        self.key_action = {}
        self.ctrl_shortcuts = {pygame.K_x: self.clipboard_cut,
                               pygame.K_c: self.clipboard_copy,
                               pygame.K_v: self.clipboard_paste,
                               pygame.K_a: self.select_all,
                               pygame.K_z: self.undo,
                               }


        console_msg("Editor row width =" + str(self.row_width), 8)
Esempio n. 6
0
 def __init__(self, world, location, name='sentry'):
     super().__init__(world, name, ROBOT_SPRITE_FILE, (16, 28), 2)
     self.set_position(location)
     # DEBUG convert source to a list of chars,
     # so that it can be handled the same as the editor code
     source = 'print("hi")'
     self.source_code = []
     line = []
     for char in source:
         line.append(char)
     self.source_code.append(line)
     console_msg("robot source loaded", 0)
Esempio n. 7
0
    def update(self):
        # process all the keystrokes in the event queue

        printable = "1234567890-=[]#;',./abcdefghijklmnopqrstuvwxyz " \
                    '!"£$%^&*()_+{}~:@<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key in self.key_action:
                    # handle all the special keys
                    self.key_action[event.key]()
                elif pygame.key.get_mods() & pygame.KMOD_CTRL:
                    # handle the keyboard shortcuts
                    if event.key in self.ctrl_shortcuts:
                        self.ctrl_shortcuts[event.key]()
                else:
                    # handle all the printable characters
                    if event.unicode != '' and event.unicode in printable:
                        self.add_keystroke(event.unicode)

            elif event.type == pygame.KEYUP:
                if event.key in (pygame.K_LSHIFT, pygame.K_RSHIFT):
                    self.stop_selecting()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                # check if the click happened within the editor area
                if pygame.mouse.get_pos()[Y] > self.height:
                    mouse_button = {1: self.left_click,
                                    # 2: middle button
                                    # 3: right button
                                    4: self.cursor_up,  # scroll up
                                    5: self.cursor_down,  # scroll down
                                    }
                    if event.button in mouse_button:
                        mouse_button[event.button]()
            elif event.type == pygame.MOUSEBUTTONUP:
                self.mouse_up()

            # we also have to handle the quit event, since the main loop
            # isn't watching events while the editor is open
            # we don't actually want to quit the game though
            # TODO prompt user to save code
            elif event.type == pygame.QUIT:
                console_msg("WARNING: Save code before quitting?", 2)

        if self.selecting:
            # use the mouse to update the selected block,
            # provided SHIFT is not held down
            # this keeps mouse and keyboard selections
            # from interfering with each other
            if not (pygame.key.get_mods() & pygame.KMOD_SHIFT):
                self.cursor_to_mouse_pos()
Esempio n. 8
0
 def run_program(self, source):
     """ pass the text in the puzzle solution to the interpreter"""
     p = interpreter.VirtualMachine(self.robot)
     p.load(source)
     result, errors = p.compile()
     if result is False:  # check for syntax errors
         # TODO display these using in-game dialogs
         if p.compile_time_error:
             error_msg = p.compile_time_error['error']
             error_line = p.compile_time_error['line']
             console_msg('BIT found a SYNTAX ERROR:', 5)
             msg = error_msg + " on line " + str(error_line)
             console_msg(msg, 5)
     else:
         result, errors = p.run()  # set the program going
Esempio n. 9
0
    def __init__(self,
                 world,
                 name,
                 sprite_file,
                 size_in_pixels,
                 height_in_blocks=1):
        super().__init__(world, name, sprite_file, size_in_pixels)
        self.height_in_blocks = height_in_blocks
        self.collidable = True
        self.set_trigger_test(world.blocks.trigger_test)
        self.set_collision_test(world.blocks.collision_test)
        self.busy = False  # used to block code execution during movement
        self.speaking = False
        self.speech_bubble = None
        self.python_interpreter = VirtualMachine(self)
        console_msg(name + " command interpreter initialised", 2)
        self.source_code = []

        self.jets = []  # the particle streams that appear when flying
        # create 2 jets, 1 for each leg
        # the origin coordinates are just zero,
        # since they will be set each frame
        for j in range(2):
            self.jets.append(
                Jet(
                    self.world,  # link back to the game world
                    (0, 0),  # dummy start position
                    (0, 1),  # initial velocity vector
                ))
        self.wobble = []  # random drift when hovering
        rx = 4
        ry = 2
        for i in range(32):
            x = i / 2 - 8  # rx * math.cos(i*2*math.pi/32)
            y = ry * math.sin(i * 2 * math.pi / 32) - ry - 2
            self.wobble.append((x, y))
        for i in range(31, -1, -1):
            x = i / 2 - 8  # rx * math.cos(i*2*math.pi/32)
            y = -ry * math.sin(i * 2 * math.pi / 32) - ry - 2
            self.wobble.append((0, 0))
            # self.wobble.append((x, y))
        self.wobble_counter = 0
        self.take_off_animation = []  # take off animation sequence
        for i in range(32):
            self.take_off_animation.append((0, 0))
Esempio n. 10
0
    def clipboard_paste(self):
        """ paste the clipboard contents into the editor window
        currently this does not validate the clipboard contents
        It assumes text is encoded using UTF-8
        and ignores all non-UTF-8 characters
        Text pasted from pycharm (and possibly IDLE too?) is encoded as HTML
        but this seems to paste ok for now
        """
        console_msg("PASTE, 8")
        self.save_history()
        # strip trailing nulls
        clipboard_text = pygame.scrap.get(pygame.SCRAP_TEXT) \
            .decode("utf-8", errors='ignore').replace('\0', '')

        for char in clipboard_text:
            # paste the chars in the keyboard, 1 at a time
            if char is chr(13):
                self.carriage_return(undo=False, pasting=True)
            elif chr(32) <= char <= chr(126):  # only allow ASCII
                self.add_keystroke(char, undo=False)
Esempio n. 11
0
 def run_program(self):
     """ pass the text in the editor to the interpreter"""
     # run_enabled is set false on each run
     # and cleared using the reset button
     if self.python_interpreter.run_enabled:
         p = self.python_interpreter  # for brevity
         p.load(self.get_source_code())
         result, errors = p.compile()
         if result is False:  # check for syntax errors
             # TODO display these using in-game dialogs
             if p.compile_time_error:
                 error_msg = p.compile_time_error['error']
                 error_line = p.compile_time_error['line']
                 console_msg(self.name + ' SYNTAX ERROR:', 5)
                 msg = error_msg + " on line " + str(error_line)
                 console_msg(msg, 5)
         else:
             result, errors = p.run()  # set the program going
         return result, errors
     return False, "RUN NOT ENABLED"
Esempio n. 12
0
    def check(self, character):
        # check if the flagpole has been activated
        trigger_rect = pygame.Rect(self.blocks[0].x, self.blocks[0].y,
                                   BLOCK_SIZE, BLOCK_SIZE)
        if (isinstance(character, Person) and not self.activated
                and character.location.colliderect(trigger_rect)):
            # unfurl the flag
            console_msg(self.name + " complete!", 1)
            # pass the level name to the save function
            self.world.complete_level(self.name)
            self.activated = True
        elif self.activated:
            # update the animation frame for the waving effect
            if self.flap_count > 0:
                self.frame_number = self.frame_number + .1
                if self.frame_number >= self.frame_count:
                    self.frame_number = 4.0
                    self.flap_count -= 1

                f = int(self.frame_number)
                for b in self.blocks:
                    b.image = b.frames[f]
Esempio n. 13
0
 def left_click(self):
     # check whether to click a button or reposition the cursor
     mouse_pos = (pygame.mouse.get_pos()[X], pygame.mouse.get_pos()[Y] -
                  self.screen.get_size()[Y] + self.height)
     if self.surface.get_rect().collidepoint(mouse_pos):
         button_result = self.buttons.click(mouse_pos)
         if button_result is None:
             self.cursor_to_mouse_pos()
             # begin marking a selection at the current position
             self.selecting = True
         else:
             # clicking a button should never affect text selection
             self.selecting = False
             if button_result == button_tray.RUN:
                 self.run_program()
             elif button_result == button_tray.STOP:
                 console_msg("Execution halted.", 1)
                 self.python_interpreter.halt()
             elif button_result == button_tray.LOAD:
                 self.load_program()
             elif button_result == button_tray.SAVE:
                 self.save_program()
             elif button_result == button_tray.CHANGE_COLOR:
                 self.color_switch()
Esempio n. 14
0
 def convert_to_lines(self):
     """ convert the raw editor characters into lines of source code
      so that they can be saved/parsed etc conveniently"""
     console_msg("Converting to lines...", 8)
     source = []
     line_number = 0
     while line_number < len(self.text):
         # join the chars on this line into a single string
         # and remove trailing whitespace
         line = ''.join(self.text[line_number]).rstrip()
         # check for a continuation character (\)
         while line and line.rstrip()[-1] == '\\':
             line_number += 1
             # remove continuation char and join lines
             line = line.rstrip('\\') + \
                 ''.join(self.text[line_number]).lstrip()
             console_msg("continuation line=" + line, 8)
         source.append(line)
         line_number += 1
     console_msg("...done", 8)
     return source
Esempio n. 15
0
    def __init__(self, screen, bypass = False):
        """ displays the main menu and ensures that the user is logged in
        before proceeding. If bypass==True the menu creates a dummy
        session, used for testing."""
        console_msg('Main menu', 0)
        self.screen = screen
        # this flag prevents certain key actions from automatically repeating
        # it is cleared when any key is released
        self.repeat_lock = False
        self._quit = False
        self._return_to_game = False
        self.clock = pygame.time.Clock()

        self.title_y_pos = 100
        self.title_size = 28
        self.items_y_pos = 370
        self.title = "Main Menu"
        self.items = ["Play", "Options", "Quit:"]
        self.selected_item = -1  # start off with nothing selected
        self.session = None

        if bypass:
            self.session = Session("dummy_user", "dummy_class")
            self._return_to_game = True
        else:
            # load the fonts
            if pygame.font.get_init() is False:
                pygame.font.init()
                console_msg("Font system initialised", 2)
            # we explicitly load all required fonts
            # so that the TTF files can be bundled to run on other PCs
            self.menu_title_font = pygame.font.Font(MENU_FONT_FILE, 48)
            self.menu_title_bg_font = pygame.font.Font(MENU_FONT_FILE, 50)
            self.menu_font = pygame.font.Font(MENU_FONT_FILE, 32)
            self.menu_input_font = pygame.font.Font(CODE_FONT_FILE, 32)
            console_msg("Menu font loaded", 3)
            self.input_dialog = MenuInputDialog(self.screen,
                                "Input",
                                self.menu_input_font)
Esempio n. 16
0
    def __init__(self, screen, display, session):
        console_msg('Initialising world.', 0)
        self.screen = screen
        self.display = display
        self.session = session

        # load play/rewind icon images
        self.rewinding = False
        self.rewind_rotation = 0
        self.rewind_icon = pygame.image.load(REWIND_ICON_FILE).convert()
        self.rewind_icon.set_colorkey((255, 255, 255), RLEACCEL)
        self.rewind_hover_icon = pygame.image.load(
            REWIND_HOVER_ICON_FILE).convert()
        self.rewind_hover_icon.set_colorkey((255, 255, 255), RLEACCEL)

        self.play_icon = pygame.image.load(PLAY_ICON_FILE).convert()
        self.play_icon.set_colorkey((255, 255, 255), RLEACCEL)
        self.play_hover_icon = pygame.image.load(
            PLAY_HOVER_ICON_FILE).convert()
        self.play_hover_icon.set_colorkey((255, 255, 255), RLEACCEL)
        self.play_disabled_icon = pygame.image.load(
            PLAY_DISABLED_ICON_FILE).convert()
        self.rewind_button_rect = pygame.Rect(REWIND_ICON_POS, (64, 64))
        self.play_button_rect = pygame.Rect(PLAY_ICON_POS, (64, 64))
        # when True the play button is displayed and programs can be run
        # once a program runs, this is set to false and the rewind button
        # is shown instead.
        self.run_enabled = True

        # load scenery layers
        self.scenery = scenery.Scenery(self.display, 'Day', 'Field')

        self.camera = Camera()

        # location of the game area on the window
        # used to scroll the game area out of the way of the code editor
        # this can't be done by the camera, because the editor is always just 'below' the visible part of the map
        # regardless of where the camera is currently panned to. In other words, the editor is not part of the
        # game world.
        self.game_origin = [0, 0]

        # load fonts
        if pygame.font.get_init() is False:
            pygame.font.init()
            console_msg("Font system initialised", 2)
        # we're not using the built-in SysFont any more
        # so that the TTF file can be bundled to run on other PCs
        self.code_font = pygame.font.Font(CODE_FONT_FILE, 18)
        console_msg("Deja Vu Sans Mono font loaded", 3)
        self.grid_font = pygame.font.Font(GRID_FONT_FILE, 8)
        console_msg("Pixel font loaded", 3)

        # load puzzle blocks
        self.blocks = blocks.BlockMap(self, BLOCK_TILE_DICTIONARY_FILE,
                                      BLOCK_TILESET_FILE, self.camera)
        console_msg("Map loaded", 1)

        self.puzzle = 0  # TODO: load current progress from log file
        self.session.set_current_level(self.blocks.get_puzzle_name(
            self.puzzle))
        self.session.save_header()

        # initialise the environmental dust effect
        # DEBUG disabled due to looking bad
        # self.dust_storm = DustStorm(self)

        # load character sprites
        self.player = characters.Person(self, 'player', CHARACTER_SPRITE_FILE,
                                        (16, 20))
        console_msg("player sprite initialised", 1)
        self.dog = characters.Robot(
            self,
            'dog',
            DOG_SPRITE_FILE,
            (16, 16),
        )
        console_msg("BIT sprite initialised", 1)
        self.player.set_position(self.blocks.get_player_start(self.puzzle))
        self.dog.set_position(self.blocks.get_dog_start(self.puzzle))

        self.dog.facing_right = False
        self.show_fps = False
        # this flag prevents certain key actions from automatically repeating
        # it is cleared when any key is released
        self.repeat_lock = False

        # intialise the python interpreter and editor
        if pygame.scrap.get_init() is False:
            pygame.scrap.init()
        console_msg("Clipboard initialised", 2)

        self.editor = code_editor.CodeWindow(screen, 300, self.code_font,
                                             self.dog, self.session)
        input_height = self.code_font.get_linesize() * 3
        self.input = input_dialog.InputDialog(screen, input_height,
                                              self.code_font)
        console_msg("Editors initialised", 2)

        # load robot sentries for this level
        self.sentries = sentry.load_sentries(self, level=1)
        # load puzzles for this level
        #        puzzle.load_puzzles(1, self)

        # initialise info signposts
        self.signposts = Signposts(self.code_font)
        console_msg("Info panels initialised", 7)

        self.playing = True  # true when we are playing a level (not a menu)
        self.frame_draw_time = 1
        self.frame_counter = 0
        self.clock = pygame.time.Clock()
Esempio n. 17
0
    def check_keyboard_and_mouse(self):
        # input handling is moved here to avoid the main loop getting
        # too cluttered
        pressed = pygame.key.get_pressed()

        if pressed[K_a]:
            self.player.moving_left = True
            self.player.moving_right = False
        elif pressed[K_d]:
            self.player.moving_left = False
            self.player.moving_right = True

        # DEBUG give player the ability to fly!
        # elif pressed[K_w]:
        #     self.player.moving_down = False;
        #     self.player.moving_up = True
        # elif pressed[K_s]:
        #     self.player.moving_down = True;
        #     self.player.moving_up = False
        if pressed[K_w] or pressed[K_s]:
            if pressed[K_w]:
                self.camera.pan(-2)
            #                    self.camera_pan[Y] -= 2
            else:
                self.camera.pan(2)
        #                    self.camera_pan[Y] += 2
        elif not self.blocks.show_grid:
            self.camera.recentre()
        #                self.camera_pan[Y] = int(self.camera_pan[Y] * 0.9)

        if pressed[K_ESCAPE]:
            # only show editor when it is completely hidden
            # this prevents it immediately reshowing after hiding
            if self.game_origin[Y] == 0:
                self.editor.show()

        # the number keys allow jumping directly to that puzzle
        # this is only enabled if the user has map editing privileges
        if ALLOW_MAP_EDITOR:
            level_shortcuts = [
                K_0, K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9
            ]
            for k in level_shortcuts:
                if pressed[k]:
                    self.puzzle = level_shortcuts.index(k)
                    self.rewind_level()

        if self.blocks.map_edit_mode:
            ctrl = pygame.key.get_mods() & KMOD_CTRL
            shift = pygame.key.get_mods() & KMOD_SHIFT

            # these actions do not auto repeat when held down
            if not self.repeat_lock:
                self.repeat_lock = True

                if pressed[K_F9]:
                    console_msg("Saving map...", 1, line_end='')
                    self.blocks.save_grid()
                    console_msg("done", 1)
                elif pressed[K_RIGHT]:
                    self.blocks.cursor_right()
                elif pressed[K_LEFT]:
                    self.blocks.cursor_left()
                elif pressed[K_UP]:
                    if ctrl:
                        self.camera.pan(-BLOCK_SIZE)
                    else:
                        self.blocks.cursor_up()
                elif pressed[K_DOWN]:
                    if ctrl:
                        self.camera.pan(BLOCK_SIZE)
                    else:
                        self.blocks.cursor_down()
                elif pressed[K_LEFTBRACKET]:  # [
                    # not used, now we have a block palette on-screen
                    #                        self.blocks.previous_editor_tile()
                    pass
                elif pressed[K_RIGHTBRACKET]:  # ]
                    #                        self.blocks.next_editor_tile()
                    pass
                elif pressed[K_BACKSPACE]:
                    if self.blocks.mover_is_selected():
                        console_msg("deleting mover", 8)
                        self.blocks.remove_moveable_group()
                    elif self.blocks.trigger_is_selected():
                        console_msg("deleting trigger", 8)
                        self.blocks.remove_trigger()
                    else:
                        self.blocks.blank_editor_tile()
                elif pressed[K_RETURN]:
                    # change/add a block
                    # at the current grid cursor location
                    self.blocks.change_block()
                elif pressed[K_TAB]:
                    # switch between midground and foreground block layers
                    self.blocks.switch_layer()
                elif pressed[K_r]:
                    # reset all block triggers and movers
                    self.blocks.reset()
                elif pressed[K_h]:
                    # home the cursor to the centre of the screen
                    self.blocks.home_cursor()
                elif pressed[K_m]:
                    # turn the selection into a movable group
                    self.blocks.create_mover()
                elif pressed[K_t]:
                    # turn the block at the cursor into a trigger
                    # or link an existing trigger to a mover
                    self.blocks.set_trigger()
                elif pressed[K_l]:
                    # toggle random mode for the trigger actions
                    # if the cursor is currently on a trigger
                    self.blocks.toggle_trigger_randomness()
                elif pressed[K_INSERT]:
                    # insert a new column of blocks at the cursor
                    self.blocks.insert_column()
                elif pressed[K_DELETE]:
                    # remove a column at the cursor
                    self.blocks.delete_column()
                else:
                    self.repeat_lock = False  # reset, since no key pressed

                    for event in pygame.event.get():
                        if event.type == pygame.MOUSEBUTTONDOWN:
                            mouse_pos = (
                                pygame.mouse.get_pos()[X] / SCALING_FACTOR +
                                self.camera.scroll_x(),
                                pygame.mouse.get_pos()[Y] / SCALING_FACTOR +
                                self.camera.scroll_y())
                            if event.button == 1:  # left click
                                if shift:
                                    self.blocks.select_block(mouse_pos, 'add')
                                else:
                                    # just select a single block
                                    self.blocks.select_block(mouse_pos, 'set')
                            elif event.button == 3:  # right click
                                self.blocks.select_block(mouse_pos, 'pick')
                            # 2: middle button
                            # 4: scroll up
                            # 5: scroll down

        # DEBUG stats
        if pressed[K_f]:
            if not self.repeat_lock:
                # toggle fps stats
                self.show_fps = not self.show_fps
                if not self.show_fps:
                    self.frame_counter = 0

        if pressed[K_g]:
            ctrl = pygame.key.get_mods() & KMOD_CTRL
            shift = pygame.key.get_mods() & KMOD_SHIFT
            if not self.repeat_lock:
                if ALLOW_MAP_EDITOR and ctrl and shift:
                    self.blocks.toggle_map_editor()
                else:
                    self.blocks.toggle_grid()
                self.repeat_lock = True

        # check the mouse to see if any buttons were clicked
        # currently just the rewind and play button
        self.check_buttons()

        # check if any signposts or info panels were clicked
        # button 0 is left click
        if pygame.mouse.get_pressed(num_buttons=5)[0]:
            self.blocks.signposts.check_signpost_at(pygame.mouse.get_pos(),
                                                    self.camera.scroll())
Esempio n. 18
0
 def stop_selecting(self):
     self.selecting = False
     console_msg("End selection", 8)
Esempio n. 19
0
 def start_selecting(self):
     self.selecting = True
     self.selection_start = (self.cursor_col, self.cursor_line)
     console_msg("Begin selection", 8)
Esempio n. 20
0
def load_puzzles(level, world):
    # load all the puzzles for a given level from the file
    file_name = PUZZLE_FILE
    with open(file_name, 'r') as file:
        lines = file.readlines()
        i = 0
        # look for the start of a puzzle
        while i < len(lines) and lines[i] != PUZZLE_START:
            i += 1
        if i < len(lines):
            # get level number
            i += 1
            level = eval(lines[i])
            # get puzzle name
            i += 1
            name = lines[i][:-1]  # strip the trailing CR+LF
            i += 1
            # get location of the sentry that will host the puzzle
            sentry_position = eval(lines[i])
            sentry = Sentry(sentry_position)

            # get the instructions for the puzzle
            i += 1
            instructions = convert_to_f_string(lines[i][:-1])

            # get the puzzle data (parameters for the puzzle)
            i += 1
            data = []
            # data is stored as tuples representing the range of possible values
            # for each item. If there are exactly 2 numeric values in the tuple,
            # it is interpreted as the lower and upper bounds for randint()
            # otherwise it is treated as a list for choice()
            data_strings = eval(lines[i])  # the list of tuples for all the parameters
            for item in data_strings:
                if len(item) == 2 and isinstance(item[0], int) and isinstance(item[1], int):
                    data.append(random.randint(int(item[0]), int(item[1])))
                else:
                    data.append(random.choice(item))
            print(eval(instructions))  # DEBUG will this pick up the f string param?

            # get the source code for the exemplar solution
            i += 1
            print(data)
            if lines[i] == SOLUTION_START:
                i += 1
                solution_source = []
                while lines[i] != SOLUTION_END and i < len(lines):
                    solution_source.append(eval(convert_to_f_string(lines[i][:-1])))
                    i += 1
                print(solution_source)
                self.run_program(solution_source)
                if i >= len(lines):
                    console_msg("Error: missing end_of_solution in puzzle file!", 0)
            else:
                console_msg("Error: missing start_of_solution in puzzle file!", 0)
        else:
            # ran off the end of the file
            console_msg('Error parsing puzzle file!', 0)

    def run_program(self, source):
        """ pass the text in the puzzle solution to the interpreter"""
        p = interpreter.VirtualMachine(self.robot)
        p.load(source)
        result, errors = p.compile()
        if result is False:  # check for syntax errors
            # TODO display these using in-game dialogs
            if p.compile_time_error:
                error_msg = p.compile_time_error['error']
                error_line = p.compile_time_error['line']
                console_msg('BIT found a SYNTAX ERROR:', 5)
                msg = error_msg + " on line " + str(error_line)
                console_msg(msg, 5)
        else:
            result, errors = p.run()  # set the program going
Esempio n. 21
0
 def clipboard_copy(self):
     console_msg("COPY", 8)
Esempio n. 22
0
 def clipboard_cut(self):
     console_msg("CUT", 8)
     self.save_history()
Esempio n. 23
0
 def __init__(self, input_combo, action):
     self.combo = input_combo  # string representing the event eg CTRL+S or ESCAPE or LEFT_CLICK
     self.modifier_keys = get_modifier_list(input_combo)  # list of pygame KMOD_xxx values eg KMOD_SHIFT
     self.action = action  # the function that is called when the input event is detected
     console_msg("Registering event for " + self.combo + " mods=" + str(self.modifier_keys), 9)
Esempio n. 24
0
    def update(self, focus):
        """update all the game world stuff
        focus is the character that the camera follows
        This is the dog when a program is running on BIT, otherwise the player"""

        display = self.display  # for brevity

        frame_start_time = time.time_ns()  # used to calculate fps

        # track the camera with the focus character, but with a bit of lag
        self.camera.update(focus)

        # render the background
        # OLD RENDER METHOD: self.scenery.draw_background(display, self.camera.scroll())
        self.scenery.draw(self.camera.scroll())
        # draw the 'midground' blocks behind the characters
        self.blocks.update_midground(display, self.camera.scroll())

        # move and render the player sprite
        self.player.update(display, self.camera.scroll())

        # move and render the dog
        self.dog.update(display, self.camera.scroll())

        # draw all the robot sentries
        for s in self.sentries:
            s.update(display, self.camera.scroll())

        # draw the 'foreground' blocks in front of the characters
        # this is just foliage and other cosmetic stuff
        self.blocks.update_foreground(display, self.camera.scroll())

        # update the input window and editor, if necessary
        # the input window takes precedence if both are open
        if self.input.is_active():
            self.input.update()
        elif self.editor.is_active():
            self.editor.update()
            # still need to check if buttons outside the editor were clicked
            self.check_buttons()
        else:
            # only handle keystrokes for game control
            # if the code editor isn't open
            self.check_keyboard_and_mouse()

            # process all other events to clear the queue
            for event in pygame.event.get():
                if event.type == KEYUP:
                    self.repeat_lock = False  # release the lock
                if event.type == QUIT:
                    self.playing = False

        if self.show_fps:
            self.frame_counter += 1
            if self.frame_counter > 60:
                self.frame_counter = 0
                console_msg(
                    'frame draw:{0}ms fps:{1} render budget left:{2}ms'.format(
                        self.frame_draw_time / 1000000,
                        int(1000000000 / self.frame_draw_time),
                        int((1000000000 - 60 * self.frame_draw_time) /
                            1000000)), 1)

        # scroll the editor in and out of view as required
        if self.editor.is_active():
            if self.game_origin[Y] > -self.editor.height:
                self.game_origin[Y] -= EDITOR_POPUP_SPEED
            self.editor.draw()
        elif self.game_origin[Y] < 0:
            self.game_origin[Y] += EDITOR_POPUP_SPEED

        # scale the rendering area to the actual game window
        self.screen.blit(pygame.transform.scale(display, WINDOW_SIZE),
                         self.game_origin)

        # the input window and code editor sit below the game surface
        # ie at a higher Y value, not below in the sense of a different layer
        editor_position = (self.game_origin[X],
                           self.game_origin[Y] + WINDOW_SIZE[Y])
        self.screen.blit(self.editor.surface, editor_position)

        # draw the input window, if it is currently active
        if self.input.is_active():
            self.input.draw()
            input_dialog_position = (self.game_origin[X], self.game_origin[Y] +
                                     WINDOW_SIZE[Y] - self.input.height)
            self.screen.blit(self.input.surface, input_dialog_position)

        # overlay any speech bubbles and info windows at the native resolution
        if self.dog.speaking:
            position = self.dog.speech_position()
            position[X] = (position[X] - self.camera.scroll_x()
                           ) * SCALING_FACTOR + self.game_origin[X]
            position[Y] = (position[Y] - self.camera.scroll_y()
                           ) * SCALING_FACTOR + self.game_origin[Y]
            self.screen.blit(self.dog.get_speech_bubble(), position)

        # do the same for any sentries
        for s in self.sentries:
            if s.speaking:
                position = s.speech_position()
                position[X] = (position[X] - self.camera.scroll_x()
                               ) * SCALING_FACTOR + self.game_origin[X]
                position[Y] = (position[Y] - self.camera.scroll_y()
                               ) * SCALING_FACTOR + self.game_origin[Y]
                self.screen.blit(s.get_speech_bubble(), position)

        self.blocks.signposts.update_open_signs(self.screen,
                                                self.camera.scroll(),
                                                self.game_origin)

        # draw the swirling dust - DEBUG disabled due to looking bad
        # self.dust_storm.update(self.screen, self.game_origin[Y], scroll)

        # draw the grid overlay next so it is on top of all blocks
        if self.blocks.show_grid:
            self.blocks.draw_grid(self.screen, self.game_origin)
        # previously, the grid took the colour from the editor choice
        #                                  self.editor.get_fg_color())

        # draw the map editor info panel and block palette
        if self.blocks.map_edit_mode:
            self.blocks.draw_edit_info_box(self.screen)
            # self.blocks.draw_block_palette(self.screen, self.game_origin)

        # draw the rewind button in the top right corner
        if self.rewinding:
            # update the rotation animation
            self.rewind_rotation = (self.rewind_rotation + 10)
            if self.rewind_rotation >= 360:
                self.rewind_rotation = 0
                self.rewinding = False
            rewind_animation_icon = pygame.transform.rotate(
                self.rewind_hover_icon, self.rewind_rotation)
            icon_size = rewind_animation_icon.get_size()
            self.screen.blit(rewind_animation_icon,
                             (REWIND_ICON_POS[X] + 32 - icon_size[X] / 2,
                              REWIND_ICON_POS[Y] + 32 - icon_size[Y] / 2))
        else:
            if self.rewind_button_rect.collidepoint(pygame.mouse.get_pos()):
                self.screen.blit(self.rewind_hover_icon, REWIND_ICON_POS)
            else:
                self.screen.blit(self.rewind_icon,
                                 REWIND_ICON_POS,
                                 special_flags=BLEND_RGB_MULT)
        # play button
        if self.dog.get_interpreter().run_enabled:
            if self.play_button_rect.collidepoint(pygame.mouse.get_pos()):
                self.screen.blit(self.play_hover_icon, PLAY_ICON_POS)
            else:
                self.screen.blit(self.play_icon,
                                 PLAY_ICON_POS,
                                 special_flags=BLEND_RGB_MULT)
        else:
            self.screen.blit(self.play_disabled_icon,
                             PLAY_ICON_POS,
                             special_flags=BLEND_RGB_MULT)

            # TODO self.end_of_level_display()
        pygame.display.update()  # actually display

        self.frame_draw_time = time.time_ns() - frame_start_time
        self.clock.tick(60)  # lock the framerate to 60fps