terom@185: terom@358: #include "Application.hh" terom@185: terom@411: #include terom@185: #include terom@409: #include terom@389: #include terom@185: #include terom@185: terom@389: enum ArgumentCodes { terom@389: ARG_HELP = 'h', terom@389: ARG_PORT = 'p', terom@389: ARG_SERVER = 's', terom@389: ARG_CLIENT = 'c', terom@389: ARG_GRAPHICS = 'g', terom@389: ARG_FULLSCREEN = 'F', terom@389: ARG_RESOLUTION = 'R', terom@389: terom@409: ARG_LIST_MODES = 0xff01, terom@409: ARG_VERSION = 0xff02, terom@409: ARG_TERRAIN_SEED = 0xff03, terom@409: ARG_TERRAIN_SIZE = 0xff04, terom@409: terom@389: }; terom@389: terom@409: terom@409: Main::Main (void) : terom@409: graphics_enabled(false), terom@409: net_port(NETWORK_PORT_STR), terom@409: net_server(false), terom@409: net_connect("") terom@409: { terom@409: terom@409: } terom@185: terom@358: /** terom@358: * Set the arg_* members terom@358: */ terom@389: bool Main::parse_args (int argc, char **argv) { terom@358: // set up the options terom@389: args.add_option(ARG_HELP, "help", "", terom@389: "display argument help and exit"); terom@389: terom@389: args.add_option(ARG_PORT, "port", "PORT", terom@389: "set network port used"); terom@389: terom@389: args.add_option(ARG_SERVER, "server", "", terom@389: "act as a network server"); terom@389: terom@389: args.add_option(ARG_CLIENT, "client", "SERVERHOST", terom@389: "act as a network client"); terom@389: terom@389: args.add_option(ARG_GRAPHICS, "graphics", "", terom@389: "run graphics/local input. Implied with --connect"); terom@389: terom@389: args.add_option(ARG_FULLSCREEN, "fullscreen", "", terom@389: "run graphics in fullscreen mode"); terom@389: terom@389: args.add_option(ARG_RESOLUTION, "resolution", "WIDTHxHEIGHT", terom@389: "set graphics resolution"); terom@389: terom@389: args.add_option(ARG_LIST_MODES, "list-modes", "", terom@389: "output a list of available display modes and exit"); terom@185: terom@409: args.add_option(ARG_TERRAIN_SEED, "terrain-seed", "SEED", terom@409: "set seed for terrain random generator"); terom@409: terom@409: args.add_option(ARG_TERRAIN_SIZE, "terrain-size", "WIDTHxHEIGHT", terom@409: "set terrain size for random generator"); terom@409: terom@397: args.add_option(ARG_VERSION, "version", "", terom@397: "output application version and exit"); terom@397: terom@358: // extra state terom@392: bool resolution_default = true; terom@358: terom@358: try { terom@358: // parse args terom@358: args.parse_args(argc, argv); terom@267: terom@358: } catch (CL_Error &e) { terom@358: throw ArgumentError(e.message); terom@358: } terom@267: terom@358: while (args.next()) { terom@358: switch (args.get_key()) { terom@389: case ARG_HELP: terom@389: args.print_help(); terom@389: return false; terom@389: terom@389: case ARG_PORT: terom@409: net_port = args.get_argument(); terom@358: break; terom@358: terom@389: case ARG_SERVER: terom@409: net_server = true; terom@358: break; terom@358: terom@389: case ARG_CLIENT: terom@409: net_connect = args.get_argument(); terom@358: break; terom@358: terom@389: case ARG_GRAPHICS: terom@409: graphics_enabled = true; terom@358: break; terom@358: terom@389: case ARG_FULLSCREEN: terom@411: display.fullscreen = true; terom@392: terom@392: // choose best resolution unless explicitly set terom@392: if (resolution_default) { terom@411: const CL_DisplayMode best_mode = graphics::Display::getBestMode(); terom@392: const CL_Size best_resolution = best_mode.get_resolution(); terom@392: terom@411: display.resolution = PixelDimensions(best_resolution.width, best_resolution.height); terom@392: } terom@392: terom@389: break; terom@389: terom@389: case ARG_RESOLUTION: terom@411: display.resolution = parse_arg_dimensions(args.get_argument(), "--resolution"); terom@392: resolution_default = false; terom@389: break; terom@389: terom@389: case ARG_LIST_MODES: terom@389: dump_display_modes(); terom@389: return false; terom@389: terom@397: case ARG_VERSION: terom@397: dump_version(); terom@397: return false; terom@397: terom@409: case ARG_TERRAIN_SEED: terom@409: terrain.random_seed = parse_arg_int(args.get_argument(), "--terrain-seed"); terom@409: break; terom@409: terom@409: case ARG_TERRAIN_SIZE: terom@409: terrain.dimensions = parse_arg_dimensions(args.get_argument(), "--terrain-size"); terom@409: break; terom@409: terom@358: case CL_CommandLine::REST_ARG: terom@409: throw ArgumentError("Trailing arguments: " + args.get_argument()); terom@358: terom@358: default: terom@409: throw ArgumentError(std::string() + "Unknown argument key: " + (char) args.get_key()); terom@358: terom@358: } terom@358: } terom@358: terom@358: // check for invalid combinations of arugments terom@409: if (net_server and !net_connect.empty()) terom@358: throw ArgumentError("cannot be both server and client"); terom@358: terom@358: // enable graphics by default unless server terom@409: if (!net_server) terom@409: graphics_enabled = true; terom@389: terom@389: // continue terom@389: return true; terom@389: } terom@389: terom@409: int Main::parse_arg_int (const std::string &arg_val, const char *arg_name) { terom@409: int int_val; terom@409: terom@409: // read using istringstream terom@409: std::istringstream ss(arg_val); terom@409: terom@409: if (!(ss >> int_val)) terom@409: throw ArgumentError(std::string() + "invalid integer arugment for " + arg_name + ": " + arg_val); terom@409: terom@409: return int_val; terom@409: } terom@409: terom@411: PixelDimensions Main::parse_arg_dimensions (const std::string &arg_val, const char *arg_name) { terom@389: unsigned int w, h; terom@389: terom@389: // sccanf as unsigned terom@409: if (sscanf(arg_val.c_str(), "%ux%u", &w, &h) != 2) terom@409: throw ArgumentError(std::string() + "invalid format for " + arg_name + ": " + arg_val); terom@389: terom@411: return PixelDimensions(w, h); terom@389: } terom@389: terom@389: void Main::dump_display_modes (void) { terom@411: const std::vector &modes = graphics::Display::getDisplayModes(); terom@389: terom@389: std::cout << "Available display modes:" << std::endl; terom@389: terom@389: for (std::vector::const_iterator it = modes.begin(); it != modes.end(); it++) terom@389: std::cout << "\t" << it->get_resolution().width << "x" << it->get_resolution().height << std::endl; terom@358: } terom@397: terom@397: void Main::dump_version (void) { terom@397: std::cout << PROJECT_LONG_NAME << " version " << PROJECT_VERSION << " built " << PROJECT_BUILD_TIMESTAMP << std::endl; terom@397: } terom@358: terom@358: /** terom@358: * IT BEGAN IN AFRIKA terom@358: */ terom@358: int Main::main (int argc, char **argv) { terom@358: // initialize the ClanLib components that we use terom@358: CL_SetupCore setup_core; terom@358: CL_SetupDisplay setup_disp; terom@358: CL_SetupGL setup_gl; terom@358: terom@358: try { terom@389: // parse arugments, exit if false terom@389: if (parse_args(argc, argv) == false) terom@389: return 0; terom@358: terom@358: // our engine terom@358: Engine engine; terom@409: terom@409: // setup game unless client terom@409: if (net_connect.empty()) terom@409: engine.setupGame(terrain); terom@358: terom@358: // setup graphics terom@409: if (graphics_enabled) terom@411: engine.setupGraphics(display); terom@358: terom@358: // setup either network server, client or singleplayer terom@409: if (net_server) { terom@409: engine.setupNetworkServer(net_port); terom@358: terom@409: } else if (!net_connect.empty()) { terom@409: engine.setupNetworkClient(net_connect, net_port); terom@358: terom@358: } else { terom@358: engine.setupSinglePlayer(); terom@185: } terom@185: terom@358: // run the main loop terom@358: engine.run(); terom@358: terom@358: // succesful return terom@358: return 0; terom@358: terom@358: } catch (ArgumentError &e) { terom@358: std::cerr << e.what() << std::endl; terom@358: args.print_help(); terom@185: terom@358: // XXX: handle --help terom@358: return 1; terom@358: } catch (CL_Error &e) { terom@358: std::cerr << "main: CL_Error:" << e.message << std::endl; terom@185: terom@358: return 1; terom@185: terom@358: } catch (std::exception &e) { terom@358: std::cerr << "FATAL [uncaught_exception] " << e.what() << std::endl; terom@185: terom@358: return 1; terom@358: } terom@358: } terom@185: