1 /*
2  * GameController.hpp
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 #ifndef LM_CLIENT_GAMECONTROLLER_HPP
26 #define LM_CLIENT_GAMECONTROLLER_HPP
27 
28 #include "GameWindow.hpp"
29 #include "GraphicalMap.hpp"
30 #include "ClientNetwork.hpp"
31 #include "TextManager.hpp"
32 #include "SoundController.hpp"
33 #include "TableBackground.hpp"
34 #include "ServerBrowser.hpp"
35 #include "ClientConfiguration.hpp"
36 #include "TransitionManager.hpp"
37 #include "ChatLog.hpp"
38 #include "common/PathManager.hpp"
39 #include "common/PacketReader.hpp"
40 #include "common/misc.hpp"
41 #include "common/GameParameters.hpp"
42 #include "common/WeaponReader.hpp"
43 #include "common/Polygon.hpp"
44 #include "GraphicalPlayer.hpp"
45 #include "Radar.hpp"
46 #include "Font.hpp"
47 #include "ScrollArea.hpp"
48 #include "ScrollBar.hpp"
49 #include "MapReceiver.hpp"
50 #include "ArbitraryMenu.hpp"
51 #include "TextMenuItem.hpp"
52 #include "ListMenuItem.hpp"
53 #include "Form.hpp"
54 #include "RadialBackground.hpp"
55 #include "RadialMenu.hpp"
56 #include "GraphicsCache.hpp"
57 #include "TextInput.hpp"
58 
59 #include <string>
60 #include <vector>
61 #include <map>
62 #include <memory>
63 
64 namespace LM {
65 	class TiledGraphic;
66 	class IPAddress;
67 	class Weapon;
68 
69 	class GameController {
70 	public:
71 		static const Color		BLUE_COLOR;
72 		static const Color		RED_COLOR;
73 		static const Color		BRIGHT_GREEN;
74 		static const Color		BRIGHT_ORANGE;
75 		static const Color		BLUE_SHADOW;
76 		static const Color		RED_SHADOW;
77 		static const Color		TEXT_COLOR;
78 		static const Color		TEXT_SHADOW;
79 		static const Color		GREYED_COLOR;
80 		static const Color		GREYED_SHADOW;
81 		static const Color		TEXT_BG_COLOR;
82 		static const Color		BUTTON_HOVER_COLOR;
83 		static const Color		BUTTON_HOVER_SHADOW;
84 
85 		const static int MESSAGE_DISPLAY_TIME;
86 		const static unsigned int MAX_MESSAGES_TO_DISPLAY;
87 		const static int SHOT_DISPLAY_TIME;
88 		const static uint64_t MUZZLE_FLASH_LENGTH;
89 		const static int GATE_WARNING_FLASH_LENGTH;
90 		const static double RANDOM_ROTATION_SCALE;
91 		const static int GATE_STATUS_RECT_WIDTH;
92 		const static int FROZEN_STATUS_RECT_WIDTH;
93 		const static int ENERGY_BAR_WIDTH;
94 		const static int COOLDOWN_BAR_WIDTH;
95 		const static int STATUS_BAR_HEIGHT;
96 		const static int DOUBLE_CLICK_TIME;
97 		const static int NETWORK_TIMEOUT_LIMIT;
98 		const static int TEXT_LAYER;
99 		const static unsigned int PING_FREQUENCY;
100 		const static unsigned int CHAT_TRANSITION_TIME;
101 		const static unsigned int CHAT_LIMIT;
102 
103 	private:
104 		struct KeyBindings {
105 			int quit;
106 			int jump;
107 			int show_overlay;
108 			int show_menu;
109 			int open_chat;
110 			int open_team_chat;
111 			int open_console;
112 			int send_chat;
113 			int weapon_1;
114 			int weapon_2;
115 			int weapon_3;
116 			int weapon_4;
117 			int weapon_5;
118 			int weapon_6;
119 			int weapon_7;
120 			int weapon_8;
121 		};
122 
123 		enum {
124 			SHOW_MENUS = 0,
125 			GAME_IN_PROGRESS = 1,
126 			GAME_OVER = 2,
127 			SHOW_OPTIONS_MENU = 3,
128 			SHOW_SERVER_BROWSER = 4
129 		};
130 
131 		struct Message {
132 			Text*		message;
133 			Transition*	transition;
134 			uint64_t	timeout;
135 		};
136 
137 		PathManager& 	m_path_manager;
138 		ClientConfiguration* m_configuration;
139 
140 		GameWindow* 	m_window;
141 		ClientNetwork	m_network;
142 		TextManager*	m_text_manager;
143 		SoundController* m_sound_controller;
144 		TransitionManager m_transition_manager;
145 		ServerBrowser*	m_server_browser;
146 		ChatLog*	m_chat_log;
147 		Font*		m_font;
148 		Font*		m_bold_font;
149 		Font*		m_medium_font;
150 		Font*		m_menu_font;
151 		Font*		m_large_menu_font;
152 
153 		std::string	m_name;
154 		std::string 	m_client_version;
155 		std::string	m_input_text;
156 		std::vector<Message> m_messages;
157 		std::vector<std::pair<Graphic*, unsigned int> > m_shots;
158 		int		m_protocol_number;
159 		int 		m_screen_width;
160 		int 		m_screen_height;
161 		int		m_map_width;
162 		int		m_map_height;
163 		Polygon		m_map_polygon;
164 		int 		m_pixel_depth;
165 		int		m_game_state;
166 		bool 		m_fullscreen;
167 		bool		m_quit_game;
168 		bool		m_restart;
169 		bool		m_offline_mode;
170 		double		m_offset_x;
171 		double		m_offset_y;
172 		double		m_mouse_x;
173 		double		m_mouse_y;
174 		Uint8*		m_keys;
175 		KeyBindings	m_key_bindings;
176 		KeyBindings 	m_alt_key_bindings;
177 		std::map<uint32_t, GraphicalPlayer> m_players;
178 		uint32_t 	m_player_id;
179 		bool		m_holding_gate;
180 		int		m_gate_lower_sounds[2];
181 		uint64_t	m_last_clicked;
182 		uint64_t	m_join_sent_time;
183 		uint64_t	m_muzzle_flash_start;
184 		uint64_t	m_last_weapon_switch;
185 
186 		uint64_t	m_last_damage_time;
187 		uint64_t	m_last_recharge_time;
188 		uint64_t	m_time_to_unfreeze;
189 		uint64_t	m_total_time_frozen;
190 
191 		uint64_t	m_round_end_time;
192 		uint64_t	m_last_ping_sent;
193 		uint32_t	m_current_ping_id;
194 		uint64_t	m_ping;
195 		uint64_t	m_framerate;
196 
197 		// TEMPORARY SPRITE CODE
198 		GraphicsCache	m_graphics_cache;
199 
200 		GraphicGroup 	blue_player;
201 		Sprite*		blue_sprite;
202 		Sprite*		blue_back_arm;
203 		GraphicGroup 	red_player;
204 		Sprite*		red_sprite;
205 		Sprite*		red_back_arm;
206 		Sprite*		m_crosshairs;
207 		TextInput*	m_chat_input;
208 		TableBackground* m_chat_window_back;
209 		Transition*	m_chat_window_transition_x;
210 		Transition*	m_chat_window_transition_y;
211 
212 		TextMenuItem*	m_version_nag1;
213 		TextMenuItem*	m_version_nag2;
214 
215 		Sprite*		m_logo;
216 		TableBackground* m_menu_back;
217 
218 		TextMenuItem*	m_item_resume;
219 		TextMenuItem*	m_item_disconnect;
220 		ArbitraryMenu	m_main_menu;
221 		ArbitraryMenu	m_options_menu;
222 		Form		m_options_form;
223 
224 		size_t		m_num_resolutions;
225 		size_t		m_resolution_selected;
226 		std::vector<std::pair<int, int> > m_resolutions;
227 
228 		bool		m_show_overlay;
229 		TableBackground* m_overlay_background;
230 		std::map<std::string, Text*> m_overlay_items;
231 		ScrollBar* 	m_overlay_scrollbar;
232 		ScrollArea*	m_overlay_scrollarea;
233 
234 		RadialBackground* m_weapon_selector_back;
235 		RadialMenu*	m_weapon_selector;
236 
237 		TableBackground* m_red_gate_status_rect;
238 		TableBackground* m_blue_gate_status_rect;
239 		TableBackground* m_red_gate_status_rect_back;
240 		TableBackground* m_blue_gate_status_rect_back;
241 		Graphic*	m_red_gate_status_text;
242 		Graphic*	m_blue_gate_status_text;
243 		uint64_t	m_last_gate_packet_seq_no[2];
244 
245 		Graphic*	m_gate_warning;
246 		uint64_t	m_gate_warning_time;
247 
248 		TableBackground* m_frozen_status_rect;
249 		TableBackground* m_frozen_status_rect_back;
250 		Graphic*	m_frozen_status_text;
251 
252 		TableBackground* m_energy_bar;
253 		TableBackground* m_energy_bar_back;
254 		Graphic*	m_energy_text;
255 
256 		TableBackground* m_cooldown_bar;
257 		TableBackground* m_cooldown_bar_back;
258 		bool		m_cooldown_updated;
259 		Graphic*	m_curr_weapon_image;
260 
261 		void		update_visible_elements();
262 
263 		// RADAR CODE BY JEFFREY
264 		Radar*		m_radar;
265 		void		set_radar_mode(RadarMode mode); // wrapper around Radar::set_mode
266 
267 		// TEMPORARY MAP CODE BY ANDREW
268 		GameParameters	m_params;
269 		GraphicalMap*	m_map;
270 		std::auto_ptr<MapReceiver>	m_map_receiver;
271 
272 		// NEW WEAPON CODE
273 		Weapon*		m_current_weapon;
274 		std::map<std::string, Weapon*>	m_weapons;
275 
276 		// NEW INPUT CODE
277 		TextInput*	m_focus;
278 		TextInput*	m_name_input;
279 		TableBackground* m_name_bar_back;
280 		bool		m_team_chatting;
281 
282 		Weapon*		get_weapon(const std::string& name);
283 		void		init_weapon_selector();
284 		void		set_weapons();
285 		void		update_curr_weapon_image();
286 		void		reset_weapons(); // Call reset() on all weapons. Call at end of every round.
287 		void		clear_weapons(); // Remove all weapons, handling memory management.
288 
289 		// Server Browsing/Scanning
290 		IPAddress	m_metaserver_address;
291 		uint32_t	m_current_scan_id;
292 
293 		static uint32_t	get_next_scan_id();
294 		void		preinit(ClientConfiguration* config);
295 		void		init(GameWindow* window);
296 		void		process_input();
297 		const GraphicalPlayer* get_player_by_id(uint32_t player_id) const;
298 		GraphicalPlayer* get_player_by_id(uint32_t player_id);
299 		GraphicalPlayer* get_player_by_name(const char* name);
300 		void		send_my_player_update();
301 		void		attempt_jump();
302 
303 		// Scan a particular server:
304 		void		scan_server(const IPAddress& server_address);
305 		void		ping_server(const IPAddress& server_address);
306 
307 		// Scan the local network for servers:
308 		void		scan_local_network();
309 
310 		// Connect to the meta server to scan the Internet
311 		void		contact_metaserver();
312 
313 		bool		load_map(const char* map_name, int map_revision);
314 		void		request_map();
315 		void		init_map(int map_width, int map_height);
316 
317 		// Display legalese in the chat window
318 		void		display_legalese();
319 
320 		void		send_ack(const PacketReader& packet);
321 
322 		// Misc. helpers
323 
324 		// Return the current angle (in radians) from the player to the crosshairs
325 		//  Doesn't take into account the player rotation
326 		double		get_crosshairs_angle() const;
327 
328 		void		add_front_arm(GraphicGroup& group, const char* sprite_name);
329 		void		populate_graphic_group(GraphicGroup& group, const char* str);
330 		void		make_front_arm_graphic(GraphicGroup& player_sprite, const char* arm, const char* gun_normal, const char* gun_firing);
331 
332 	public:
333 		explicit GameController(PathManager& pathman, ClientConfiguration* config);
334 		GameController(PathManager& pathman, ClientConfiguration* config, int width, int height, bool fullscreen =false, int depth =24);
335 		~GameController();
336 
337 		void		run(int lockfps=60);
338 		void		set_screen_dimensions(int width, int height);
339 		void		initialize_key_bindings();
340 		void		parse_key_input();
341 		void		move_objects(float timescale);
342 		void		connect_to_server(const IPAddress& server_address, char team =0);
343 		void		connect_to_server(int servernum);
344 		void		disconnect();
345 		void		send_message(std::string message);
346 		void		send_team_message(std::string message);
display_message(std::string message)347 		void		display_message(std::string message) { display_message(message, TEXT_COLOR, TEXT_SHADOW); }
348 		void		display_message(std::string message, Color, Color, bool bold=false);
349 		void		send_gate_hold(bool holding);
350 		void		set_gate_hold(bool holding);
351 		void		set_players_visible(bool visible);
352 		void		process_mouse_click(SDL_Event event);
353 		void		send_animation_packet(std::string sprite, std::string field, int value);
354 		void		send_name_change_packet(const char* new_name);
355 		void		send_team_change_packet(char new_team);
356 		void		toggle_main_menu(bool visible);
357 		void		toggle_options_menu(bool visible);
358 		void		toggle_score_overlay(bool visible);
359 		void		toggle_server_browser(bool visible);
360 		void		set_hud_visible(bool visible);
361 		void		update_energy_bar(int new_energy=-1);
362 		void		update_cooldown_bar(double new_cooldown=-1);
363 		void		delete_server_browser_entry(int num);
364 		void		change_team_scores(int bluescore, int redscore);
365 		void 		update_individual_scores();
366 		void 		update_individual_score_line(int count, const GraphicalPlayer& currplayer);
367 		void		delete_individual_score(const GraphicalPlayer& currplayer);
368 		void		set_player_name(std::string name);
get_player_name() const369 		std::string	get_player_name() const { return m_name; };
370 		void		clear_players();
371 		bool		wants_restart();
372 		void		reset_options();
373 		void		next_weapon();
374 		void		previous_weapon();
375 		void		change_weapon(const char* name);
376 		void		change_weapon(unsigned int n); // change to the nth weapon (0-indexed)
377 		void		change_weapon(Weapon* weapon);
378 		void		recreate_name(GraphicalPlayer* player);
379 		std::string	get_server_address();
380 		std::string	format_time_from_millis(uint64_t milliseconds);
381 		void		reduce_freeze_time(uint64_t milliseconds);
382 		void		freeze(uint64_t how_long);
383 		void		unfreeze();
384 
385 		// This is a COMPATIBILITY WRAPPER around the more general shoot_in_line() function below.
386 		// Code should be migrated to use the new function.
387 		Point		find_shootable_object(Point startpos, double direction, BaseMapObject*& hit_map_object, Player*& hit_player);
388 
389 		// A HitObject represents an object (player or map object) that was hit by a weapon discharge
390 		struct HitObject {
391 			double		distance;	// Distance from where the weapon was discharged
392 			Point		point;		// Where in the arena that the object was hit
393 			BaseMapObject*	map_object;	// The map object that was hit (if applicable, NULL otherwise)
394 			Player*		player;		// The player that was hit (if applicable, NULL otherwise)
395 
396 			HitObject (double distance, Point point, BaseMapObject* map_object =NULL);
397 			HitObject (double distance, Point point, Player* player);
operator <LM::GameController::HitObject398 			bool operator<(const HitObject& other) const { return distance < other.distance; }
399 		};
400 
401 		// Starting from the given point, shoot in a STRAIGHT LINE in the given direction,
402 		// and populate the given set with the objects that are hit.
403 		void		shoot_in_line(Point startpos, double direction, std::multiset<HitObject>& hit_objects);
404 
405 		// Find all hit objects in the given shape, and populate the given set
406 		// Planned for future: bool penetrate_players, bool penetrate_obstacles
407 		std::list<Point> shoot_in_region(const Shape& shape, const Point& pivot, std::list<Player*>& hit_players);
408 
409 		// Check if an object is occluded from view from a given point
410 		Point		is_occluded(const Point& startpos, Point& objectcenter, HitObject& object);
411 
412 		// Scan both the local network and the meta server for servers:
413 		void		scan_all();
414 
415 		// Contact the meta server to check for upgrades
416 		void		check_for_upgrade();
417 
418 		// Network callbacks:
419 		void		send_packet(const PacketWriter& packet);
420 		void		send_reliable_packet(const PacketWriter& packet);
421 		void		welcome(PacketReader& reader);
422 		void		player_update(PacketReader& reader);
423 		void		announce(PacketReader& reader);
424 		void		leave(PacketReader& reader);
425 		void		weapon_discharged(PacketReader& reader);
426 		void		player_hit(PacketReader& reader);
427 		void		message(PacketReader& reader);
428 		void		gate_update(PacketReader& reader);
429 		void		new_round(PacketReader& reader);
430 		void		round_over(PacketReader& reader);
431 		void		round_start(PacketReader& reader);
432 		void		spawn_packet(PacketReader& reader);
433 		void		score_update(PacketReader& reader);
434 		void		animation_packet(PacketReader& reader);
435 		void		request_denied(PacketReader& reader);
436 		void		name_change(PacketReader& reader);
437 		void		team_change(PacketReader& reader);
438 		void		map_info_packet(PacketReader& reader);
439 		void		map_object_packet(PacketReader& reader);
440 		void		game_param_packet(PacketReader& reader);
441 		void		player_died(PacketReader& reader);
442 		void		weapon_info_packet(PacketReader& reader);
443 		void		server_info(const IPAddress& server_address, PacketReader& reader);
444 		void		upgrade_available(const IPAddress& server_address, PacketReader& reader);
445 		void		hole_punch_packet(const IPAddress& server_address, PacketReader& reader);
446 		void		excessive_packet_drop();
447 
448 		// Sound callbacks:
449 		void		play_sound(const char* name);
450 		void		sound_finished(int channel);
451 
452 		// Weapon callbacks:
453 		void		activate_radar_blip(const Player& player);
454 		void		show_muzzle_flash();
455 		void		show_bullet_impact(Point position, const char* sprite_name);
456 		void		register_front_arm_graphic(Player& player, const char* normal, const char* firing);
457 
458 		// Damage the player by this amount of energy
459 		// aggressor is the player who did the damage, or NULL if no player did it (e.g. hazerdous map object)
460 		// Returns true if the player died as a result, false if the player is still alive
461 		bool		damage (int amount, const Player* aggressor);
462 	};
463 }
464 
465 #endif
466 
467