1 /*
2  * main.cpp
3  *
4  * This file is part of Leges Motus, a networked, 2D shooter set in zero gravity.
5  *
6  * Copyright 2009-2010 Andrew Ayer, Nathan Partlan, Jeffrey Pfau
7  *
8  * Leges Motus is free and open source software.  You may redistribute it and/or
9  * modify it under the terms of version 2, or (at your option) version 3, of the
10  * GNU General Public License (GPL), as published by the Free Software Foundation.
11  *
12  * Leges Motus is distributed in the hope that it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14  * PARTICULAR PURPOSE.  See the full text of the GNU General Public License for
15  * further detail.
16  *
17  * For a full copy of the GNU General Public License, please see the COPYING file
18  * in the root of the source code tree.  You may also retrieve a copy from
19  * <http://www.gnu.org/licenses/gpl-2.0.txt>, or request a copy by writing to the
20  * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307  USA
22  *
23  */
24 
25 #include "GameController.hpp"
26 #include "ClientSDL.hpp"
27 #include "ClientConfiguration.hpp"
28 #include "common/Exception.hpp"
29 #include "common/PathManager.hpp"
30 #include "common/misc.hpp"
31 #include "common/network.hpp"
32 #include "common/team.hpp"
33 #include <iostream>
34 #include <sstream>
35 
36 #ifdef __APPLE__
37 extern "C" {
38 #include "mac_bridge.h"
39 }
40 #elif defined(__WIN32)
41 #include <Windows.h>
42 #endif
43 
44 using namespace LM;
45 using namespace std;
46 
clean_exit()47 extern "C" void clean_exit() {
48 	SDL_Event quit_event;
49 	quit_event.type = SDL_QUIT;
50 	SDL_PushEvent(&quit_event);
51 }
52 
53 namespace {
54 	bool run_from_finder = false;
55 
display_usage(const char * progname)56 	void display_usage(const char* progname) {
57 		cout << "Usage: " << progname << " [OPTION]" << endl;
58 		cout << "Options:" << endl;
59 		cout << "  -n NAME	set your player name" << endl;
60 		cout << "  -t red|blue	set your team" << endl;
61 		cout << "  -s SERVER	set the hostname of the server" << endl;
62 		cout << "  -p PORTNO	set the port number of the server" << endl;
63 		cout << "  -w WIDTH	set the screen width, in pixels" << endl;
64 		cout << "  -h HEIGHT	set the screen height, in pixels" << endl;
65 		cout << "  -f 		run the game in fullscreen" << endl;
66 		cout << "  -?, --help	display this help, and exit" << endl;
67 		cout << "      --version\tdisplay version information and exit" << endl;
68 	}
69 
display_legalese()70 	void display_legalese() {
71 		cout << "Copyright 2009-2010 Andrew Ayer, Nathan Partlan, Jeffrey Pfau" << endl;
72 		cout << "Leges Motus is free and open source software; see the source for copying conditions." << endl;
73 		cout << "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." << endl;
74 	}
75 
display_version()76 	void display_version() {
77 		cout << "Leges Motus" << endl;
78 		cout << "A networked, 2D shooter set in zero gravity" << endl;
79 		cout << endl;
80 		display_legalese();
81 	}
82 }
83 
main(int argc,char * argv[])84 extern "C" int main(int argc, char* argv[]) try {
85 	ClientSDL		client_sdl;
86 	GameController*		game_controller;
87 	int			width = 0;
88 	int			height = 0;
89 	bool			fullscreen = false;
90 	char			team = 0;
91 	string			server = "";
92 	unsigned int		portno = DEFAULT_PORTNO;
93 	string			name = "";
94 	IPAddress		server_address;
95 
96 	for (int i = 1; i < argc; i++) {
97 		if (strcmp(argv[i], "-f") == 0) {
98 			fullscreen = true;
99 		} else if (strcmp(argv[i], "-w") == 0 && argc > i+1) {
100 			width = atoi(argv[i+1]);
101 			++i;
102 		} else if (strcmp(argv[i], "-h") == 0 && argc > i+1) {
103 			height = atoi(argv[i+1]);
104 			++i;
105 		} else if (strcmp(argv[i], "-s") == 0 && argc > i+1) {
106 			server = argv[i+1];
107 			++i;
108 		} else if (strcmp(argv[i], "-p") == 0 && argc > i+1) {
109 			portno = atoi(argv[i+1]);
110 			++i;
111 		} else if (strcmp(argv[i], "-n") == 0 && argc > i+1) {
112 			name = argv[i+1];
113 			++i;
114 		} else if (strcmp(argv[i], "-t") == 0 && argc > i+1) {
115 			team = parse_team_string(argv[i+1]);
116 			if (!is_valid_team(team)) {
117 				cerr << argv[0] << ": Unrecognized team `" << argv[i+1] << "'" << endl;
118 				display_usage(argv[0]);
119 				return 2;
120 			}
121 			++i;
122 		} else if (strcmp(argv[i], "--version") == 0) {
123 			display_version();
124 			return 0;
125 		} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-?") == 0) {
126 			display_usage(argv[0]);
127 			return 0;
128 		} else if (strncmp(argv[i], "-psn", 4) == 0) {
129 			run_from_finder = true;
130 		} else {
131 			cerr << argv[0] << ": Unrecognized option `" << argv[i] << "'" << endl;
132 			display_usage(argv[0]);
133 			return 2;
134 		}
135 	}
136 
137 	PathManager	pathman(argv[0]);
138 
139 	bool restart = true;
140 	while(restart) {
141 		if (!server.empty() && !resolve_hostname(server_address, server.c_str(), portno)) {
142 			cerr << "Hostname of requested server not found: " << server << endl;
143 			return 1;
144 		}
145 
146 		if (has_terminal_output()) {
147 			cout << "Welcome to Leges Motus." << endl;
148 			display_legalese();
149 		}
150 
151 		ClientConfiguration config;
152 
153 		if (width > 0 && height > 0) {
154 			// Use the specified width and height
155 			game_controller = new GameController(pathman, &config, width, height, fullscreen);
156 		} else if (fullscreen) {
157 			// Use optimal settings
158 			game_controller = new GameController(pathman, &config);
159 		} else {
160 			width = config.get_int_value("screen_width");
161 			height = config.get_int_value("screen_height");
162 			fullscreen = config.get_bool_value("fullscreen");
163 			if (width == -1) {
164 				width = 800;
165 			}
166 			if (height == -1) {
167 				height = 600;
168 			}
169 			// Use the default from the config
170 			game_controller = new GameController(pathman, &config, width, height, fullscreen);
171 		}
172 
173 		if (!name.empty()) {
174 			config.set_string_value("name", name);
175 		} else {
176 			if (config.get_string_value("name") == "" || config.get_string_value("name") == "Unnamed") {
177 				config.set_string_value("name", get_username());
178 			}
179 			name = config.get_string_value("name");
180 		}
181 
182 		game_controller->set_player_name(!name.empty() ? name : get_username());
183 		if (!server.empty()) {
184 			game_controller->connect_to_server(server_address, team);
185 		}
186 
187 		game_controller->run();
188 
189 		if (game_controller->wants_restart()) {
190 			// Allow the resolution to be re-specified by the config.
191 			width = 0;
192 			height = 0;
193 			fullscreen = false;
194 
195 			// Reconnect to the server we were on.
196 			server = game_controller->get_server_address();
197 			size_t portdelim = server.find(":");
198 			if (portdelim != string::npos) {
199 				portno = atoi(server.substr(portdelim+1).c_str());
200 				server = server.substr(0, portdelim);
201 			}
202 			name = game_controller->get_player_name();
203 			game_controller->disconnect();
204 		} else {
205 			restart = false;
206 		}
207 
208 		delete game_controller;
209 	}
210 
211 	if (has_terminal_output()) {
212 		cout << "Leges Motus is now exiting.  Thanks for playing!" << endl;
213 	}
214 
215 	return 0;
216 
217 } catch (const Exception& e) {
218 	cerr << "Error: " << e.what() << endl;
219 	cerr << "1. If on X11, check that your $DISPLAY environment variable is set properly." << endl;
220 	cerr << "2. Make sure that Leges Motus has been properly installed (if compiling from source, you should have run 'make install'), OR that your $LM_DATA_DIR environment variable is set to the directory containing the game resources." << endl;
221 
222 	#ifdef __APPLE__
223 	if (run_from_finder) {
224 		toplevel_exception(e.what());
225 	}
226 	#elif defined(__WIN32)
227 	stringstream s;
228 	s << e.what() << endl;
229 	s << "Please ensure that you are running Leges Motus from the same directory as the game resources" << flush;
230 	MessageBox(NULL, s.str().c_str(), NULL, MB_OK|MB_ICONERROR);
231 	#endif
232 
233 	return 1;
234 }
235