Пример #1
0
class Scene:
    def __init__(self, player, levelcnt):
        self.levelcnt = levelcnt

        self.player = player
        self.gameOver = False
        self.timeOut = False

        self.score = 0
        self.levelUp()

        self.dontMeltLastPos = False  #True if the last position had a switch
        self.iceLastPos = False  #True if last position had a portal

    def levelUp(self):
        #set the current level
        self.levelcnt += 1
        self.curLevel = Level(self.levelcnt)  #create a new level

        self.player.__init__()
        #load level
        self.curLevel.loadLevel()
        self.levelRows, self.levelCols = self.curLevel.levelRows, self.curLevel.levelCols
        self.playerStartRow, self.playerStartCol = self.curLevel.playerStartRow, self.curLevel.playerStartCol
        self.targetRow, self.targetCol = self.curLevel.targetRow, self.curLevel.targetCol
        self.walls = self.curLevel.walls
        self.iceNum = self.curLevel.iceNum
        self.switches = self.curLevel.switches
        self.levelMin, self.levelSec = self.curLevel.levelMin, self.curLevel.levelSec
        self.countdown = Countdown(self.levelMin, self.levelSec)
        self.iceMelted = 0
        self.keyObtained = False

        #level loaded; set player data
        self.player.setPos(self.playerStartRow, self.playerStartCol)
        self.player.setBoundaries(self.walls)
        self.player.setTargetPos(self.targetRow, self.targetCol)
        if self.curLevel.hasKey: self.player.setDoorLock(self.curLevel.lockPos)

    def meltOldPos(self, oldRow, oldCol):
        #checks if the last position was a switch
        #if it was a switch, change boolean
        #if it was not a switch, melt the old position
        if self.dontMeltLastPos == False:
            self.curLevel.meltIce(oldRow, oldCol)
            self.iceMelted += 1
        else:
            self.dontMeltLastPos = False

    def updateAlivePlayer(self):
        for event in pygame.event.get():
            if event.type == QUIT: return 1
            elif event.type == MOUSEBUTTONUP:
                x, y = event.pos
                restartX1, restartY1, restartX2, restartY2 = (4, 515, 105, 538)
                if restartX1 <= x <= restartX2 and restartY1 <= y <= restartY2:
                    return 2

            elif event.type == KEYDOWN:
                if event.key == K_RIGHT: self.player.move(0, +1)
                elif event.key == K_LEFT: self.player.move(0, -1)
                elif event.key == K_UP: self.player.move(-1, 0)
                elif event.key == K_DOWN: self.player.move(+1, 0)
                else: return 0  #break for loop if a different key pressed

                oldRow, oldCol = self.player.getOldPos()
                curRow, curCol = self.player.getCurPos()
                if (oldRow != None and oldCol != None) and (oldRow != curRow or
                                                            oldCol != curCol):
                    #only melt ice and increase score when the player has made a valid move
                    coinRow, coinCol = self.curLevel.coinPos
                    keyRow, keyCol = self.curLevel.keyPos
                    lockRow, lockCol = self.curLevel.lockPos
                    pos = (curRow, curCol)
                    if pos in self.switches:
                        self.score += 10
                        self.curLevel.turnToIce(
                            curRow,
                            curCol)  #once stepped on a switch, it becomes ice
                        self.switches.remove(pos)  #switch no longer exists
                        self.player.visited.remove(
                            pos)  #player can step on switch tiles twice
                        self.meltOldPos(oldRow, oldCol)
                        self.dontMeltLastPos = True  #if "cur" pos was a switch, it was turned into ice; do not melt it
                        break

                    elif pos in self.curLevel.portals:
                        self.score += 10

                        for portal in self.curLevel.portals:
                            if pos != portal:
                                newRow, newCol = portal

                        self.curLevel.turnToIce(curRow, curCol)
                        self.player.setPos(newRow, newCol)
                        self.player.visited.remove(pos)
                        self.curLevel.portals.clear()
                        self.iceLastPos = True
                        break

                    elif self.iceLastPos:  #if the last position was a portal, scene should turn last pos to
                        self.curLevel.turnToIce(oldRow, oldCol)
                        self.iceLastPos = False
                        break

                    elif (coinRow != None
                          and coinCol != None) and (coinRow == curRow
                                                    and coinCol == curCol):
                        self.score += 50  #bonus points bc hit a coin

                    elif self.curLevel.hasKey:
                        if keyRow == curRow and keyCol == curCol:
                            self.score += 20
                            self.keyObtained = self.player.keyObtained = True
                        elif lockRow == curRow and lockCol == curCol:
                            if self.keyObtained:
                                self.score += 20
                                self.curLevel.unlockDoor()
                            else:
                                print("key not obtained; cannot unlock door")

                    self.score += 8  #not a special case tile
                    self.meltOldPos(oldRow, oldCol)

    def update(self):
        self.playerState = self.player.getPlayerState()
        self.playerWins = self.curLevel.playerWins
        timerUpdate = self.countdown.update()

        if not self.playerWins and timerUpdate == "game over":
            self.timeOut = self.gameOver = True

        elif self.playerWins:
            self.gameOver = True

        elif self.playerState == 1:  #alive
            return self.updateAlivePlayer()

        elif self.playerState == 2:  #reached target
            if self.iceMelted == self.iceNum:
                self.score += self.iceNum * 2  #bonus point for melting all ice on that level
            self.levelUp()

        elif self.playerState == 0:  #dead
            row, col = self.player.getDiedPos()
            self.curLevel.meltIce(row, col)
            self.gameOver = True
            pygame.time.delay(600)
        return 0

    def drawText(self, screen):
        font = pygame.font.Font("Krungthep.ttf", 20)
        font.set_bold(True)

        #score
        score = font.render("score: %d" % self.score, True, BLUE)
        screen.blit(score, [445, 515])

        #level
        level = font.render("level: %d" % self.levelcnt, True, BLUE)
        screen.blit(level, [5, 5])

        #ice block count
        iceMelted = str(self.iceMelted)
        if len(iceMelted) == 1: iceMelted = " " + iceMelted
        blocktxt = iceMelted + "/" + str(self.iceNum)
        blocks = font.render(blocktxt, True, BLUE)
        screen.blit(blocks, [520, 5])

        #key needed
        self.drawKeyText(screen)

    def drawKeyText(self, screen):
        font = pygame.font.Font("Krungthep.ttf", 15)
        font.set_bold(True)
        key = font.render("KEY: ", True, BLUE)
        screen.blit(key, [222, 518])
        if self.curLevel.hasKey:  #needs key
            if self.keyObtained: status = "obtained"
            else: status = "unobtained"
        else:  #does not need key
            status = "unavailable"
        keytxt = "KEY: " + status
        key = font.render(status, True, RED)
        screen.blit(key, [265, 518])

    def display(self, screen):
        BG, null = load_image("base.gif")
        screen.blit(BG, (0, 0))

        self.drawText(screen)
        self.countdown.draw(screen)

        self.curLevel.draw(screen)
        self.player.draw(screen)

        pygame.display.flip()
Пример #2
0
class Game:
    def __init__(self):
        # initialize the pygame module
        pygame.init()

        logo_name = os.path.join('assets', "logo.png")
        logo = pygame.image.load(logo_name)
        pygame.display.set_icon(logo)

        pygame.display.set_caption("Escape")
        self.screen = pygame.display.set_mode(SCREEN_SIZE)
        self.black_surface = self.screen.copy()
        self.black_surface.fill(pygame.Color("black"))

        # default font used for the timer
        self.font = pygame.font.Font(None, 100)
        self.subtext_font = pygame.font.Font(None, 25)
        self.notification_font = pygame.font.Font(None, 25)

        # specifies the middle of the screen
        self.character = Character("avatar/MC-front.png", 0, 0)
        self.camera = Coords(CHARACTER_START[X], CHARACTER_START[Y])

        # saves the camera for when enering the building
        self.camera_save = None
        self.user_input = UserInput()

        # sound
        self.ambient = pygame.mixer.Sound("assets/ambient.wav")
        self.ambient_channel = pygame.mixer.Channel(1)
        self.wind = pygame.mixer.Sound("assets/wind.wav")
        self.wind.play(-1)

        # a shit ton of time related stuff
        self.clock = pygame.time.Clock()
        self.countdown = Countdown()
        self.ticker = Ticker()
        self.fade_in_timer = Timer()
        self.display_timer = Timer()
        self.notification_timer = Timer()
        self.fade_out_timer = Timer()

        # variables for when you're in some building
        self.current_building = None
        self.buildings = create_buildings()
        self.well_area = ScaledRect(208, 354, 60, 51)

        # define a variable to control the main loop
        # where it is really only set to false if the player exits or the X button is pressed
        self.running = True
        self.state = None
        self.fade_into_main_menu()

        self.wins = create_wins()
        self.subtext_value = ""
        self.notification_value = ""

        # self.ended = False
        # self.show_ending = False

        self.end_image = None
        self.begin_image = load_image("beginlol.png",
                                      use_scale=False,
                                      return_rect=False)
        self.begin_image = pygame.transform.scale(self.begin_image,
                                                  SCREEN_SIZE)

        self.default_background = load_image('background.png',
                                             return_rect=False)
        self.building_wall_mask = load_image('background_outline.png',
                                             convert_alpha=True,
                                             return_rect=False)

        # background can change to default background or house background
        self.background = self.default_background

        # creates the start menus
        self.pause_menu = PauseMenu(self.screen)
        self.main_menu = MainMenu(self.screen)

        self.temp = []

    @property
    def in_building(self):
        return self.current_building is not None

    def play(self):
        while self.running:
            if DEBUG:
                print(STATE_DICT[self.state])
            self.handle_event()
            self.update()
            self.draw()

            self.clock.tick(60)

        if DEBUG:
            print("debug: temp =", self.temp)
            print("collected {}".format(self.character.items))

    def handle_event(self):
        self.user_input.update()
        self.ticker.update()

        # can only pause when you're in the f*****g game matey lmao
        if self.state == GAME_PLAY and self.user_input.clicked_pause(
                self.ticker.tick):
            self.pause()
        elif self.state == GAME_PAUSE:
            if self.user_input.clicked_mouse():
                pos = pygame.mouse.get_pos()
                if self.pause_menu.resume_button.border.collidepoint(pos):
                    self.unpause()
                if self.pause_menu.exit_button.border.collidepoint(pos):
                    self.running = False
            if self.user_input.clicked_pause(self.ticker.tick):
                self.unpause()

        # checks for main menu clicks
        if self.state == MAIN_MENU:
            if self.user_input.clicked_mouse():
                pos = pygame.mouse.get_pos()
                if self.main_menu.play_button.border.collidepoint(pos):
                    self.fade_outof_main_menu()
                if self.main_menu.exit_button.border.collidepoint(pos):
                    self.running = False
                    return
            if self.user_input.clicked_interact(self.ticker.tick):
                self.fade_outof_main_menu()

        # only do something if the event is of type QUIT
        if self.user_input.clicked_quit():
            # change the value to False, to exit the main loop
            self.running = False
            return

        # if the player presses interact and it's during one of the display screens
        if self.user_input.clicked_interact(self.ticker.tick):
            if BEGIN_FADE_IN <= self.state <= BEGIN_FADE_OUT:
                self.start_game_fade_in()

            if END_FADE_IN <= self.state <= END_FADE_OUT:
                self.fade_into_main_menu()

        if self.state in STATES_DISPLAY:
            if self.display_timer.ended:
                if self.state == BEGIN_DISPLAY:
                    # begin display -> fade out begin display
                    self.state = BEGIN_FADE_OUT
                    self.fade_out_timer.start(BEGIN_FADE_OUT_TIME)

                elif self.state == END_DISPLAY:
                    # end display -> fade out end display
                    self.state = END_FADE_OUT
                    self.fade_out_timer.start(END_FADE_OUT_TIME)

        if self.state in STATES_FADE_IN:
            if self.fade_in_timer.ended:
                if self.state == MAIN_MENU_FADE_IN:
                    # menu fade in to main menu
                    self.to_main_menu()

                elif self.state == BEGIN_FADE_IN:
                    # end instruction fade in
                    self.state = BEGIN_DISPLAY
                    self.display_timer.start(BEGIN_DISPLAY_TIME)

                elif self.state == GAME_FADE_IN:
                    # starts the game here (end fade in)
                    self.countdown.start()
                    self.ambient_channel.play(self.ambient)
                    self.state = GAME_PLAY

                elif self.state == END_FADE_IN:
                    # end the ending fade in
                    self.state = END_DISPLAY
                    self.display_timer.start(END_DISPLAY_TIME)

        if self.state in STATES_FADE_OUT:
            if self.fade_out_timer.ended:
                if self.state == MAIN_MENU_FADE_OUT:
                    # menu fade out -> begin fade in
                    self.state = BEGIN_FADE_IN
                    self.fade_in_timer.start(BEGIN_FADE_IN_TIME)

                elif self.state == BEGIN_FADE_OUT:
                    # begin fade out -> game fade in
                    self.start_game_fade_in()

                elif self.state == GAME_FADE_OUT:
                    # already ended the game, shows display
                    self.state = END_FADE_IN
                    self.fade_in_timer.start(END_FADE_IN_TIME)

                elif self.state == END_FADE_OUT:
                    self.fade_into_main_menu()

        # countdown ends: game ends
        if self.state == GAME_PLAY and self.countdown.ended:
            self.end()

    def update(self):
        if self.state == GAME_PLAY:
            self.countdown.update()

            velocity = self.user_input.get_velocity()
            self.camera.store_previous()
            self.camera += velocity
            if DEBUG:
                coords = self.character.get_pixel_at_feet(self.camera)
                print(coords)
                if self.user_input.clicked_debug(self.ticker.tick):
                    self.temp.append(coords)
            self.character.update(velocity, self.ticker.tick)

            if not self.in_building:
                # detects collision with walls and buildings
                pixel = (self.building_wall_mask.get_at(
                    tuple(self.character.get_pixel_at_feet(self.camera))))
                if pixel[3] > ALPHA_THRESHOLD:
                    # TODO make less sticky if possible
                    if COLLIDES:
                        # checks for each x and y if they can work
                        current_x = self.camera.x
                        current_y = self.camera.y

                        self.camera.x = self.camera.previous_x
                        self.camera.y = self.camera.previous_y

                        coords = Coords(current_x, current_y)
                        coords.x = self.camera.previous_x  # gets the new y coordinate and keeps x constant
                        pixel = (self.building_wall_mask.get_at(
                            tuple(self.character.get_pixel_at_feet(coords))))
                        if not (pixel[3] > ALPHA_THRESHOLD
                                ):  # if the new y coordinate is free
                            self.camera.y = coords.y

                        coords = Coords(current_x, current_y)
                        coords.y = self.camera.previous_y
                        pixel = (self.building_wall_mask.get_at(
                            tuple(self.character.get_pixel_at_feet(coords))))
                        if not pixel[3] > ALPHA_THRESHOLD:
                            self.camera.x = coords.x

                # checks for collecting water at the well
                if (self.well_area.collide(self.camera,
                                           self.character.proper_size)
                        and self.character.items["water_skin"] >= 1):
                    self.subtext_value = "Press {} to fill your water skin".format(
                        INTERACT_KEY)
                    if self.user_input.clicked_interact(self.ticker.tick):
                        self.character.items["water_skin"] -= 1
                        self.character.items["filled_water_skin"] += 1
                        self.notification_value = "Filled your water skin"
                        self.notification_timer.start(NOTIFICATION_TIME)

                # checks for the building shit
                for building in self.buildings:
                    if building.enters(self.character, self.camera):
                        self.subtext_value = "Press {} to enter ".format(
                            INTERACT_KEY) + building.name

                        if self.user_input.clicked_interact(self.ticker.tick):
                            self.notification_value = "Entered " + building.name
                            self.notification_timer.start(NOTIFICATION_TIME)

                            self.current_building = building
                            self.background = building.background
                            self.camera_save = self.camera.copy()

                            # resets the camera
                            building_exit_coords = building.camera_exit_coords
                            building_exit_coords.y -= self.character.rect.height // 2
                            self.camera = building_exit_coords

                # collides with any win
                for win in self.wins:
                    if win.collide(self.camera,
                                   self.character.get_rect_at_feet()):
                        # set player to escaped
                        self.character.escaped = True
                        # ambient fades out only here
                        self.ambient_channel.fadeout(AMBIENT_FADE_OUT)
                        self.end()

            else:
                # detects collision with the building walls by checking
                # if the player leaves the given rect
                coords = tuple(self.character.get_pixel_at_feet(self.camera))
                if not self.current_building.walls.rect.collidepoint(coords):
                    # TODO make less sticky if possible

                    if COLLIDES:
                        # checks for each x and y if they can work
                        current_x = self.camera.x
                        current_y = self.camera.y

                        self.camera.x = self.camera.previous_x
                        self.camera.y = self.camera.previous_y

                        coords2 = Coords(current_x, current_y)
                        coords2.x = self.camera.previous_x  # gets the new y coordinate and keeps x constant
                        if self.current_building.walls.rect.collidepoint(
                                tuple(self.character.get_pixel_at_feet(
                                    coords2))):
                            self.camera.y = coords2.y

                        coords2 = Coords(current_x, current_y)
                        coords2.y = self.camera.previous_y
                        if self.current_building.walls.rect.collidepoint(
                                tuple(self.character.get_pixel_at_feet(
                                    coords2))):
                            self.camera.x = coords2.x

                # detects collision for furniture
                for furniture in self.current_building.furniture.values():
                    if furniture.rect.collidepoint(coords):
                        # TODO make less sticky if possible
                        if COLLIDES:
                            # checks for each x and y if they can work
                            current_x = self.camera.x
                            current_y = self.camera.y

                            self.camera.x = self.camera.previous_x
                            self.camera.y = self.camera.previous_y

                            coords2 = Coords(current_x, current_y)
                            coords2.x = self.camera.previous_x  # gets the new y coordinate and keeps x constant
                            if not furniture.rect.collidepoint(
                                    tuple(
                                        self.character.get_pixel_at_feet(
                                            coords2))):
                                self.camera.y = coords2.y

                            coords2 = Coords(current_x, current_y)
                            coords2.y = self.camera.previous_y
                            if not furniture.rect.collidepoint(
                                    tuple(
                                        self.character.get_pixel_at_feet(
                                            coords2))):
                                self.camera.x = coords2.x

                # checks for collectibles
                for collectible in self.current_building.collectibles:
                    if collectible.collides(self.character, self.camera):
                        self.subtext_value = "Collect " + collectible.display_name

                        if self.user_input.clicked_interact(self.ticker.tick):
                            collectible.pick_up()
                            self.notification_value = "Collected " + collectible.display_name
                            self.notification_timer.start(NOTIFICATION_TIME)
                            self.character.items[collectible.type] += 1
                            #self.character.points += collectible.points
                            #self.character.weight += collectible.weight

                # checks whether they have left the building
                if self.current_building.exit_area.collide(
                        self.camera, self.character.get_rect_at_feet()):
                    self.subtext_value = "Press {} to leave ".format(
                        INTERACT_KEY) + self.current_building.name

                    if self.user_input.clicked_interact(self.ticker.tick):
                        self.notification_value = "Left " + self.current_building.name
                        self.notification_timer.start(NOTIFICATION_TIME)
                        self.camera = self.camera_save
                        self.current_building = None
                        self.background = self.default_background

    def draw(self):
        self.screen.fill((0, 0, 0))
        # draws the background relative to the character and countdown
        if GAME_FADE_IN <= self.state <= GAME_FADE_OUT:
            self.screen.blit(self.background,
                             (SCREEN_SIZE[X] // 2 - self.camera.x,
                              SCREEN_SIZE[Y] // 2 - self.camera.y))

            self.countdown.draw(self.screen, self.font)

            if not self.in_building:
                if DEBUG:
                    for building in self.buildings:
                        building.debug_draw_position(self.screen, self.camera)
                    for win in self.wins:
                        win.debug_draw(self.camera, self.screen)
                    self.well_area.debug_draw(self.camera, self.screen, "pink")

            else:
                # in building
                if DEBUG:
                    self.current_building.debug_draw_inner(
                        self.screen, self.camera)

                # draws all collectibles within a building
                self.current_building.collectibles.draw(
                    self.screen, self.camera)

            # draws character at the last lmao
            self.character.draw(self.screen)
            if DEBUG:
                self.character.draw_pixel(self.screen, self.camera)

            if self.state == GAME_PAUSE:
                self.pause_menu.draw(self.screen)

            # renders the display name on the bottom right of the screen
            if self.subtext_value:
                text_render = self.subtext_font.render(self.subtext_value,
                                                       True,
                                                       pygame.Color("orange"))
                # text_render = pygame.transform.scale(text_render, (text_render.get_width()*3, text_render.get_height()*3))
                text_pos = text_render.get_rect()
                text_pos.bottomleft = self.screen.get_rect().bottomleft
                self.screen.blit(text_render, text_pos)
                self.subtext_value = ""

            if self.notification_value:
                if self.notification_timer.ended:
                    self.notification_value = ""
                else:
                    text_render = self.notification_font.render(
                        self.notification_value, True, pygame.Color("orange"))
                    # text_render = pygame.transform.scale(text_render, (text_render.get_width()*3, text_render.get_height()*3))
                    text_pos = text_render.get_rect()
                    text_pos.bottomleft = self.screen.get_rect().bottomleft
                    text_pos.y -= 25
                    self.screen.blit(text_render, text_pos)

        # displays the beginning image
        if BEGIN_FADE_IN <= self.state <= BEGIN_FADE_OUT:
            self.screen.blit(self.begin_image, (0, 0))

        # displays the ending image
        if END_FADE_IN <= self.state <= END_FADE_OUT:
            self.screen.blit(self.end_image, (0, 0))

        # displays the main menu
        if self.state in (MAIN_MENU_FADE_IN, MAIN_MENU, MAIN_MENU_FADE_OUT):
            self.main_menu.draw(self.screen)

        if self.state in STATES_FADE_IN or self.state in STATES_FADE_OUT:
            if self.state in STATES_FADE_IN:
                # goes from black to normal
                alpha_value = int(255 * (self.fade_in_timer.get()))
            else:
                # goes from normal to black
                alpha_value = int(255 - 255 * (self.fade_out_timer.get()))

            self.black_surface.set_alpha(alpha_value)
            self.screen.blit(self.black_surface, (0, 0))

        pygame.display.flip()

    def start_game_fade_in(self):
        self.state = GAME_FADE_IN
        self.fade_in_timer.start(GAME_FADE_IN_TIME)

    def pause(self):
        #pygame.mixer.pause()
        self.ambient_channel.pause()
        self.countdown.pause()
        self.state = GAME_PAUSE

    def unpause(self):
        #pygame.mixer.unpause()
        self.ambient_channel.unpause()
        self.countdown.unpause()
        self.state = GAME_PLAY

    def fade_into_main_menu(self):
        # does the majority of resetting here if necessary
        # fades out if there's still sound for some reason
        self.countdown.start()
        self.countdown.pause()
        self.ambient_channel.fadeout(2)
        self.character.reset()
        for building in self.buildings:
            for collectible in building.collectibles:
                collectible.reset()
        self.camera = Coords(CHARACTER_START[X], CHARACTER_START[Y])

        self.fade_in_timer.start(MAIN_MENU_FADE_IN_TIME)
        self.state = MAIN_MENU_FADE_IN

    def to_main_menu(self):
        self.state = MAIN_MENU

    def fade_outof_main_menu(self):
        self.state = MAIN_MENU_FADE_OUT
        self.fade_out_timer.start(MAIN_MENU_FADE_OUT_TIME)

    def end(self):
        if not self.countdown.ended:
            self.countdown.pause()
        self.state = GAME_FADE_OUT
        self.fade_out_timer.start(GAME_FADE_OUT_TIME)

        # gets the end image
        if not self.character.escaped:
            self.end_image = load_image("endings/stay_death.png",
                                        return_rect=False)
        elif sum(self.character.items.values()) <= 2:
            self.end_image = load_image("endings/missing_lots_death.png",
                                        return_rect=False)
        elif self.character.has_no_items("filled_water_skin"):
            self.end_image = load_image("endings/thirst_death.png",
                                        return_rect=False)
        elif self.character.has_no_items("ugly_green_scarf"):
            self.end_image = load_image("endings/cold_death.png",
                                        return_rect=False)
        elif self.character.has_no_items("bread", "cheese", "jerky"):
            self.end_image = load_image("endings/starvation_death.png",
                                        return_rect=False)
        elif self.character.has_no_items("bandages", "bow_arrow", "cheese"):
            self.end_image = load_image("endings/bandits_death.png",
                                        return_rect=False)
        elif self.character.has_no_items("pileogold"):
            self.end_image = load_image("endings/no_money_death.png",
                                        return_rect=False)
        else:
            self.end_image = load_image("endings/win_happy.png",
                                        return_rect=False)

        self.end_image = pygame.transform.scale(self.end_image, SCREEN_SIZE)

        if DEBUG:
            print("ended!")