Example #1
0
 def apply_options(self):
     if self.resolution_custom.active:
         try:
             old_size = gg.screen_size
             gg.set_screen_size((int(self.resolution_custom_horiz.text),
                                 int(self.resolution_custom_vert.text)))
             if gg.screen_size != old_size:
                 dialog.Dialog.top.needs_resize = True
         except ValueError:
             pass
Example #2
0
 def apply_options(self):
     # Apply CUSTOM choice.
     if self.resolution_choice.list_pos == 0:
         try:
             old_size = gg.screen_size
             gg.set_screen_size((int(self.resolution_custom_horiz.text),
                                 int(self.resolution_custom_vert.text)))
             if gg.screen_size != old_size:
                 dialog.Dialog.top.needs_resize = True
         except ValueError:
             pass
Example #3
0
def main():
    # Manually "pre-parse" command line arguments for -s|--singledir and --multidir,
    # so g.get_save_folder reports the correct location of preferences file
    # We also track --debug/-d to enable some stacktraces during initialization
    for parser in sys.argv[1:]:
        if parser == "--singledir" or parser == "-s":
            g.force_single_dir = True
        elif parser == "--multidir":
            g.force_single_dir = False
        elif parser == '--debug' or parser == '-d':
            g.debug = True

    print("Singularity %s (commit: %s)" % (__version__, __release_commit__))
    print("Running under Python %s" % sys.version.replace("\n", ''))

    # Create all directories first
    dirs.create_directories(g.force_single_dir)

    # Set language second, so help page and all error messages can be translated
    from singularity.code import i18n
    i18n.set_language(force=True)

    langs = i18n.available_languages()
    language = i18n.language

    # Since we require numpy anyway, we might as well ask pygame to use it.
    try:
        import pygame
        pygame.surfarray.use_arraytype("numpy")
    except ValueError:
        if g.debug:
            raise
        raise SystemExit("Endgame: Singularity requires NumPy.")
    except ImportError:
        if g.debug:
            print("Failed to import pygame.  Python's sys.path is:")
            for d in sys.path:
                print("    %s" % str(d))
            print()
            raise
        raise SystemExit("Endgame: Singularity requires pygame.")

    import singularity.code.graphics.g as gg
    import singularity.code.graphics.theme as theme

    set_theme = None

    #configure global logger
    g.logfile = dirs.get_writable_file_in_dirs("error.log", "log")
    root_logger = logging.getLogger()

    if len(root_logger.handlers) == 0:
        try:
            try:
                root_logger.addHandler(
                    logging.FileHandler(g.logfile, delay=True))
                print(
                    "The error-log configured as %s (lazily created when something is logged)"
                    % g.logfile)
            except TypeError:  # Python < 2.6, delay not supported yet.
                root_logger.addHandler(logging.FileHandler(g.logfile))
                print("The error-log configured as %s" % g.logfile)

        except IOError as e:  # Probably access denied with --singledir. That's ok
            print("Could not use %s as log file: %s" % (g.logfile, str(e)))
            g.logfile = None
    else:
        print("Using pre-setup logging function")

    # keep g's defaults intact so we can compare after parsing options and prefs
    from singularity.code import mixer, warning
    desired_soundbuf = mixer.soundbuf

    desired_set_grab = None

    #load prefs from file:
    save_loc = dirs.get_readable_file_in_dirs("prefs.dat", "pref")

    if save_loc is not None:

        prefs = SafeConfigParser()
        try:
            with open(save_loc, "r", encoding='utf-8') as savefile:
                prefs.read_file(savefile)
        except Exception as reason:
            sys.stderr.write("Cannot load preferences file %s! (%s)\n" %
                             (save_loc, reason))
            sys.exit(1)

        if prefs.has_section("Preferences"):
            try:
                desired_language = prefs.get("Preferences", "lang")
                if desired_language in i18n.available_languages():
                    i18n.set_language(desired_language)
                else:
                    raise ValueError
            except Exception:
                sys.stderr.write("Invalid or missing 'lang' in preferences.\n")

            try:
                gg.set_fullscreen(prefs.getboolean("Preferences",
                                                   "fullscreen"))
            except Exception:
                sys.stderr.write(
                    "Invalid or missing 'fullscreen' setting in preferences.\n"
                )

            try:
                mixer.nosound = prefs.getboolean("Preferences", "nosound")
            except Exception:
                sys.stderr.write(
                    "Invalid or missing 'nosound' setting in preferences.\n")

            try:
                desired_set_grab = prefs.getboolean("Preferences", "grab")
            except Exception:
                sys.stderr.write(
                    "Invalid or missing 'grab' setting in preferences.\n")

            try:
                g.daynight = prefs.getboolean("Preferences", "daynight")
            except Exception:
                sys.stderr.write(
                    "Invalid or missing 'daynight' setting in preferences.\n")

            try:
                desired_soundbuf = prefs.getint("Preferences", "soundbuf")
            except Exception:
                sys.stderr.write(
                    "Invalid or missing 'soundbuf' setting in preferences.\n")

            xres, yres = (0, 0)

            try:
                xres = prefs.getint("Preferences", "xres")
            except Exception:
                sys.stderr.write(
                    "Invalid or missing 'xres' resolution in preferences.\n")

            try:
                yres = prefs.getint("Preferences", "yres")
            except Exception:
                sys.stderr.write(
                    "Invalid or missing 'yres' resolution in preferences.\n")

            if xres and yres:
                gg.set_screen_size((xres, yres))

            try:
                set_theme = prefs.get("Preferences", "theme")
            except Exception:
                pass  # don't be picky (for now...)

            for name in mixer.itervolumes():
                try:
                    volume = prefs.getint("Preferences", name + "_volume")
                except Exception:
                    # Work around old preferences where a float was stored by mistake
                    try:
                        volume = prefs.getfloat("Preferences",
                                                name + "_volume")
                    except Exception:
                        continue
                    else:
                        volume = int(volume) * 100

                mixer.set_volume(name, volume)

        if prefs.has_section("Warning"):
            try:
                for key in prefs.options('Warning'):

                    if key in prefs.defaults():  # Filter default key
                        continue

                    if key not in warning.warnings:  # Filter invalid warning
                        continue  # TODO: Return error

                    warning.warnings[key].active = prefs.getboolean(
                        "Warning", key)

            except Exception:
                pass  # don't be picky (for now...)

        if prefs.has_section("Textsizes"):
            for key in prefs.options('Textsizes'):
                if key in prefs.defaults():  # Filter default key
                    continue

                if key not in gg.configured_text_sizes:  # Ignore unknown text-size definitions
                    continue

                try:
                    gg.configured_text_sizes[key] = prefs.getint(
                        "Textsizes", key)
                except Exception:
                    pass  # Ignore

    #Handle the program arguments.
    desc = """Endgame: Singularity is a simulation of a true AI.
    Go from computer to computer, pursued by the entire world.
    Keep hidden, and you might have a chance."""
    parser = optparse.OptionParser(version=__full_version__,
                                   description=desc,
                                   prog="singularity")
    parser.add_option("--sound",
                      action="store_true",
                      dest="sound",
                      help="enable sound (default)")
    parser.add_option("--nosound",
                      action="store_false",
                      dest="sound",
                      help="disable sound")
    parser.add_option("--daynight",
                      action="store_true",
                      dest="daynight",
                      help="enable day/night display (default)")
    parser.add_option("--nodaynight",
                      action="store_false",
                      dest="daynight",
                      help="disable day/night display")
    parser.add_option("-l",
                      "--lang",
                      "--language",
                      dest="language",
                      type="choice",
                      choices=langs,
                      metavar="LANG",
                      help="set the language to LANG (available languages: " +
                      " ".join(langs) + ", default " + language + ")")
    parser.add_option("-g",
                      "--grab",
                      help="grab the mouse pointer",
                      dest="grab",
                      action="store_true")
    parser.add_option("--nograb",
                      help="don't grab the mouse pointer (default)",
                      dest="grab",
                      action="store_false")
    parser.add_option(
        "-s",
        "--singledir",
        dest="singledir",
        help="keep saved games and settings in the Singularity directory",
        action="store_true")
    parser.add_option(
        "--multidir",
        dest="singledir",
        help=
        "keep saved games and settings in an OS-specific, per-user directory (default)",
        action="store_false")
    parser.add_option("--soundbuf",
                      type="int",
                      help="""set the size of the sound buffer (default %s).
                        Discarded if --nosound is specified.""" %
                      mixer.soundbuf)

    display_options = optparse.OptionGroup(parser, "Display Options")
    display_options.add_option("-t",
                               "--theme",
                               dest="theme",
                               type="string",
                               metavar="THEME",
                               help="set theme to THEME")
    display_options.add_option(
        "-r",
        "--res",
        "--resolution",
        dest="resolution",
        help="set resolution to custom RES (default %dx%d)" %
        gg.default_screen_size,
        metavar="RES")
    for res in ["%dx%d" % res for res in gg.resolutions]:
        display_options.add_option("--" + res,
                                   action="store_const",
                                   dest="resolution",
                                   const=res,
                                   help="set resolution to %s" % res)
    display_options.add_option("--fullscreen",
                               action="store_true",
                               help="start in fullscreen mode")
    display_options.add_option("--windowed",
                               action="store_false",
                               help="start in windowed mode (default)")
    parser.add_option_group(display_options)

    olpc_options = optparse.OptionGroup(parser, "OLPC-specific Options")
    olpc_options.add_option("--xo1",
                            action="store_const",
                            dest="resolution",
                            const="1200x900",
                            help="set resolution to 1200x900 (OLPC XO-1)")
    olpc_options.add_option(
        "--ebook",
        help="""enables gamepad buttons for use in ebook mode.
    D-pad moves mouse, check is click. O speeds up time, X slows down time,
    and square stops time.""",
        action="store_true",
        default=False)
    parser.add_option_group(olpc_options)

    hidden_options = optparse.OptionGroup(parser, "Hidden Options")
    hidden_options.add_option("-p", help="(ignored)", metavar=" ")
    hidden_options.add_option("-d",
                              "--debug",
                              help="for finding bugs",
                              action="store_true",
                              default=False)
    hidden_options.add_option("--cheater",
                              help="for bad little boys and girls",
                              action="store_true",
                              default=False)
    # Uncomment to make the hidden options visible.
    #parser.add_option_group(hidden_options)
    (options, args) = parser.parse_args()

    if options.language is not None:
        i18n.set_language(options.language)
    if options.theme is not None:
        set_theme = options.theme
    if options.resolution is not None:
        try:
            xres, yres = options.resolution.split("x")
            gg.set_screen_size((int(xres), int(yres)))
        except Exception:
            parser.error(
                "Resolution must be of the form <h>x<v>, e.g. %dx%d." %
                gg.default_screen_size)
    if options.grab is not None:
        desired_set_grab = options.grab
    if options.fullscreen is not None:
        gg.set_fullscreen(options.fullscreen)
    if options.sound is not None:
        mixer.nosound = not options.sound
    if options.daynight is not None:
        g.daynight = options.daynight
    if options.soundbuf is not None:
        desired_soundbuf = options.soundbuf

    gg.ebook_mode = options.ebook

    g.cheater = options.cheater
    g.debug = options.debug

    import singularity.code.graphics.font as font

    # PYGAME INITIALIZATION
    #
    # Only initiliaze after reading all arguments and preferences to avoid to
    # reinitialize something again (mixer,...).
    #
    mixer.preinit(desired_soundbuf)
    pygame.init()
    mixer.update()
    font.init()
    pygame.key.set_repeat(1000, 50)

    if desired_set_grab is not None:
        pygame.event.set_grab(desired_set_grab)

    #I can't use the standard image dictionary, as that requires the screen to
    #be created.
    if pygame.image.get_extended() == 0:
        print("Error: SDL_image required. Exiting.")
        sys.exit(1)

    from singularity.code import data

    #init themes:
    data.load_themes()
    theme.set_theme(set_theme)

    gg.init_graphics_system()

    #init data:
    data.reload_all()

    # Init music
    mixer.load_sounds()
    mixer.load_music()
    mixer.play_music("music")

    #Display the main menu
    #Import is delayed until now so selected language via command-line options or
    # preferences file can be effective
    from singularity.code.screens import main_menu
    menu_screen = main_menu.MainMenu()
    try:
        menu_screen.show()
    except (SystemExit, KeyboardInterrupt):
        # exit normally when window is closed (and silently for CTRL+C)
        pass
    finally:
        # Be nice and close the window on SystemExit
        pygame.quit()
Example #4
0
 def set_resolution(self, value):
     if gg.screen_size != value:
         gg.set_screen_size(value)
         dialog.Dialog.top.needs_resize = True
Example #5
0
    def handle(self, event):
        """Sends an event through all the applicable handlers, returning
           constants.NO_RESULT if the event goes unhandled or is handled without
           requesting the dialog to exit.  Otherwise, returns the value provided
           by the handler."""
        # Get the applicable handlers.  The handlers lists are all sorted.
        # If more than one handler type is applicable, we use [:] to make a
        # copy of the first type's list, then insort_all to insert the elements
        # of the other lists in proper sorted order.
        handlers = []
        if event.type == pygame.MOUSEMOTION:
            # Compress multiple MOUSEMOTION events into one.
            # Note that the pos will be wrong, so pygame.mouse.get_pos() must
            # be used instead.
            time.sleep(1. / g.FPS)
            pygame.event.clear(pygame.MOUSEMOTION)

            # Generic mouse motion handlers.
            handlers = self.handlers.get(constants.MOUSEMOTION, [])[:]

            # Drag handlers.
            if event.buttons[0]:
                insort_all(handlers, self.handlers.get(constants.DRAG, []))
        elif event.type == pygame.USEREVENT:
            # Clear excess timer ticks.
            pygame.event.clear(pygame.USEREVENT)

            # Timer tick handlers.
            handlers = self.handlers.get(constants.TICK, [])

            # Generate repeated keys.
            if self.key_down:
                self.repeat_counter += 1
                if self.repeat_counter >= 5:
                    self.repeat_counter = 0
                    self.handle(self.key_down)
        elif event.type in (pygame.KEYDOWN, pygame.KEYUP):

            # TODO: Dynamize global key handlers.
            # TODO: Allows customization of global key handlers.
            # Important: Global key handlers should always be a combination
            # of two keys or F# keys.
            if event.key == pygame.K_RETURN and pygame.key.get_mods(
            ) & pygame.KMOD_ALT:
                if event.type == pygame.KEYDOWN:
                    g.set_fullscreen(not g.fullscreen)
                    Dialog.top.needs_resize = True

            elif event.key == pygame.K_F5:
                if event.type == pygame.KEYDOWN:
                    import singularity.code.graphics.theme as theme
                    if theme.current:
                        import singularity.code.data as data
                        theme_id = theme.current.id
                        data.load_themes()
                        theme.set_theme(theme_id, force_reload=True)

            elif event.type == pygame.KEYDOWN:
                # Generic keydown handlers.
                insort_all(handlers, self.handlers.get(constants.KEYDOWN, []))

                # Generic key event handlers.
                insort_all(handlers, self.handlers.get(constants.KEY, []))

                if event.unicode:
                    # Unicode-based keydown handlers for this particular key.
                    insort_all(handlers,
                               self.key_handlers.get(event.unicode, []))
                # Keycode-based handlers for this particular key.
                insort_all(handlers, self.key_handlers.get(event.key, []))

                # Begin repeating keys.
                if self.key_down is not event:
                    self.key_down = event
                    self.repeat_counter = -10
                    self.start_timer(force=True)
            else:  # event.type == pygame.KEYUP:
                # Stop repeating keys.
                self.key_down = None
                self.reset_timer()

                # Generic keyup handlers.
                insort_all(handlers, self.handlers.get(constants.KEYUP, []))

            # OLPC XO-1 ebook mode.
            if g.ebook_mode and event.key in KEYPAD:
                handlers = [(0, handle_ebook)]
        elif event.type == pygame.MOUSEBUTTONUP:
            # Handle mouse scrolls by imitating PageUp/Dn
            if event.button in (4, 5):
                if event.button == 4:
                    key = pygame.K_PAGEUP
                else:
                    key = pygame.K_PAGEDOWN
                fake_key(key)
                return constants.NO_RESULT

            # Mouse click handlers.
            handlers = [] + self.handlers.get(constants.CLICK, [])

            when = time.time()
            where = event.pos
            what = event.button

            old_when, old_where, old_what = self.last_click
            self.last_click = when, where, what

            if what == old_what and when - old_when < .5:
                # Taxicab distance.
                dist = (abs(where[0] - old_where[0]) +
                        abs(where[1] - old_where[1]))

                if dist < 10:
                    # Add double-click handlers, but keep the click handlers.
                    insort_all(handlers,
                               self.handlers.get(constants.DOUBLECLICK, []))
        elif event.type == pygame.VIDEORESIZE:
            # Compress multiple requests and take the last one
            events = pygame.event.get(pygame.VIDEORESIZE)
            if events:
                event = events[-1]
            new_size = event.size
            g.set_screen_size(size=new_size)
            # We call set_mode to attempt to enforce our corrected sizes.  That
            # is what it is supposed to do according to:
            #
            #   https://stackoverflow.com/questions/18285208/how-to-put-limits-on-resizing-a-window-in-pygame
            #
            # However, it is not effective in all cases (as replies to the SO
            # question above also imply).
            g.set_mode()
            Dialog.top.needs_resize = True
        elif event.type == pygame.QUIT:
            raise SystemExit
        elif event.type == pygame.VIDEOEXPOSE:
            # If a window is dragged over the singularity window, we will get a VIDEOEXPOSE event
            # to notify us to redraw the window.  The issue is easier to trigger with pygame 2
            # than with pygame 1.
            self.needs_redraw = True
            return constants.NO_RESULT

        return self.call_handlers(handlers, event)