1 #include "config.h"
2 #include "constants.h"
3 #include "gfxinterface.h"
4 #include "highscore.h"
5 #include "input.h"
6 #include "instance.h"
7 #include "managers.h"
8 #include "menu.h"
9 #include "score.h"
10 #include "stars.h"
11 #include "time_util.h"
12 #include "xpms.h"
13 #include <cstdlib>
14 #include <iostream>
15 #include <memory>
16 #include <stdexcept>
17 #include <vector>
18 
19 
20 namespace Data {
21 
22 // The following arrays are arrival trajectories defined with relative
23 // coordinates.
24 // RCEnd is the end marker.
25 
26 const RCoord hang[] = {
27 	RCoord(512,-20), RCoord(512,612), RCoord(496,662), RCoord(454,704),
28 	RCoord(414,716), RCoord(368,704), RCoord(330,662), RCoord(318,612),
29 	RCoord(330,556), RCoord(512,260),
30 	RCEnd
31 };
32 const RCoord infinity[] = {
33 	RCoord(-20,800),
34 	RCoord(460+300,544-200), RCoord(512+300,530-200),
35 	RCoord(560+300,544-200), RCoord(592+300,588-200),
36 	RCoord(598+300,618-200), RCoord(592+300,648-200),
37 	RCoord(560+300,690-200), RCoord(512+300,702-200),
38 	RCoord(512-300,702-200), RCoord(462-300,690-200),
39 	RCoord(430-300,648-200), RCoord(422-300,618-200),
40 	RCoord(428-300,588-200), RCoord(460-300,544-200),
41 	RCEnd
42 };
43 const RCoord v[] = {
44 	RCoord(-20,312), RCoord(350,550), RCoord(700,550), RCoord(800,500),
45 	RCEnd
46 };
47 const RCoord u[] = {
48 	RCoord(256,-20), RCoord(256,600), RCoord(768,600), RCoord(768,200),
49 	RCEnd
50 };
51 const RCoord loop[] = {
52 	RCoord(-20,430),
53 	RCoord(512,430), RCoord(560,444), RCoord(592,488), RCoord(598,518),
54 	RCoord(592,548), RCoord(560,590), RCoord(512,602), RCoord(462,590),
55 	RCoord(430,548), RCoord(422,518), RCoord(428,488), RCoord(460,444),
56 	RCoord(512,430), RCoord(560,444), RCoord(592,488), RCoord(598,518),
57 	RCoord(592,548), RCoord(560,590), RCoord(512,602), RCoord(462,590),
58 	RCoord(430,548), RCoord(422,518), RCoord(428,488), RCoord(460,444),
59 	RCEnd
60 };
61 const RCoord left[] =  { RCoord(-20,512),     RCoord(512,512), RCEnd };
62 const RCoord sine[] = {
63 	RCoord(-20,586), RCoord(0,566),   RCoord(20,540),  RCoord(66,524),
64 	RCoord(124,548), RCoord(152,588), RCoord(158,634), RCoord(182,676),
65 	RCoord(244,700), RCoord(302,676), RCoord(328,634), RCoord(338,588),
66 	RCoord(364,548), RCoord(422,524), RCoord(482,548), RCoord(506,588),
67 	RCEnd
68 };
69 const RCoord t_diag[] = { RCoord(-20,-20),     RCoord(512,700), RCEnd };
70 const RCoord b_diag[] = { RCoord(-20,1024+20), RCoord(512,316), RCEnd };
71 const RCoord b_zz[] = {
72 	RCoord(-20,1000), RCoord(100,1000), RCoord(0,900), RCoord(100,900),
73 	RCoord(0,800), RCoord(100,800), RCoord(0,700), RCoord(100,700),
74 	RCoord(0,600), RCoord(100,600), RCoord(0,500), RCoord(100,500),
75 	RCoord(0,400), RCoord(100,400),
76 	RCEnd
77 };
78 const RCoord t_zz[] = {
79 	RCoord(-20,100), RCoord(100,100), RCoord(0,200), RCoord(100,200),
80 	RCoord(0,300),   RCoord(100,300), RCoord(0,400), RCoord(100,400),
81 	RCoord(0,500),   RCoord(100,500), RCoord(0,600), RCoord(100,600),
82 	RCoord(0,700),   RCoord(100,700),
83 	RCEnd
84 };
85 const RCoord t_circ[] = {
86 	RCoord(20,-20), RCoord(20,194), RCoord(22,240), RCoord(30,280),
87 	RCoord(38,320), RCoord(52,360), RCoord(66,402), RCoord(88,446),
88 	RCoord(112,490), RCoord(144,532), RCoord(172,566), RCoord(212,604),
89 	RCoord(246,630), RCoord(292,660), RCoord(334,680), RCoord(394,700),
90 	RCoord(436,710), RCoord(512,716), RCoord(1024-436,710),
91 	RCoord(1024-394,700), RCoord(1024-334,680), RCoord(1024-292,660),
92 	RCoord(1024-246,630), RCoord(1024-212,604), RCoord(1024-172,566),
93 	RCoord(1024-144,532), RCoord(1024-112,490), RCoord(1024-88,446),
94 	RCoord(1024-66,402), RCoord(1024-52,360), RCoord(1024-38,320),
95 	RCoord(1024-30,280), RCoord(1024-22,240), RCoord(1024-20,194),
96 	RCEnd
97 };
98 const RCoord boing[] = {
99 	RCoord(24,1024+20), RCoord(24,796), RCoord(30,716), RCoord(40,644),
100 	RCoord(50,608), RCoord(60,576), RCoord(70,538), RCoord(80,516),
101 	RCoord(90,496), RCoord(100,476), RCoord(110,464), RCoord(120,446),
102 	RCoord(130,426), RCoord(140,420), RCoord(150,406), RCoord(160,390),
103 	RCoord(170,386), RCoord(180,376), RCoord(190,366), RCoord(200,362),
104 	RCoord(210,356), RCoord(220,350), RCoord(230,346), RCoord(240,344),
105 	RCoord(250,340), RCoord(260,339), RCoord(278,338),
106 	RCoord(2*278-260,339), RCoord(2*278-250,340), RCoord(2*278-240,344),
107 	RCoord(2*278-230,346), RCoord(2*278-220,350), RCoord(2*278-210,356),
108 	RCoord(2*278-200,362), RCoord(2*278-190,366), RCoord(2*278-180,376),
109 	RCoord(2*278-170,386), RCoord(2*278-160,390), RCoord(2*278-150,406),
110 	RCoord(2*278-140,420), RCoord(2*278-130,426), RCoord(2*278-120,446),
111 	RCoord(2*278-110,464), RCoord(2*278-100,476), RCoord(2*278-90,496),
112 	RCoord(2*278-80,516), RCoord(2*278-70,538), RCoord(2*278-60,576),
113 	RCoord(2*278-50,608), RCoord(2*278-40,644), RCoord(2*278-30,716),
114 	RCoord(2*278-24, 796),
115 	RCEnd
116 };
117 const RCoord drop128[] = { RCoord(128,-20), RCoord(128,700), RCEnd };
118 const RCoord drop256[] = { RCoord(256,-20), RCoord(256,700), RCEnd };
119 const RCoord drop384[] = { RCoord(384,-20), RCoord(384,700), RCEnd };
120 const RCoord drop512[] = { RCoord(512,-20), RCoord(512,700), RCEnd };
121 const RCoord drop640[] = { RCoord(640,-20), RCoord(640,700), RCEnd };
122 const RCoord drop768[] = { RCoord(768,-20), RCoord(768,700), RCEnd };
123 const RCoord drop896[] = { RCoord(896,-20), RCoord(896,700), RCEnd };
124 
125 // The following arrays fully define the game levels with the
126 // following parameters:
127 // - delay in frames before aliens convoy creation
128 // - XPM data to draw the alien
129 // - percentage of window width taken by the aliens convoy
130 // - aliens convoy trajectory
131 // - boolean, true iff the convoy is mirrored
132 // - boolean, true iff the convoy is made of two mirrored half-convoys
133 
134 const ConvoyData cd1[] = {
135 	{  0, alien1_xpm,  50, hang, false, true },
136 	{100, alien1_xpm,  50, hang, false, true },
137 	{100, alien1_xpm,  50, hang, false, true },
138 	{100, alien1_xpm,  50, hang, false, true },
139 	{100, alien1_xpm,  30, hang, false, true },
140 	{ 10, alien13_xpm, 15, hang, false, true },
141 	{0,0,0,0,false,false}
142 };
143 const ConvoyData cd2[] = {
144 	{200, alien2_xpm,  50, v,    false, false },
145 	{150, alien2_xpm,  50, v,    true,  false },
146 	{150, alien2_xpm,  50, v,    false, false },
147 	{100, alien2_xpm,  50, v,    true,  false },
148 	{100, alien2_xpm,  30, hang, false, true },
149 	{ 10, alien13_xpm, 15, hang, false, true },
150 	{0,0,0,0,false,false}
151 };
152 const ConvoyData cd3[] = {
153 	{200, alien3_xpm, 50, t_diag, false, false },
154 	{200, alien3_xpm, 50, t_diag, true,  false },
155 	{200, alien3_xpm, 50, t_diag, false, true },
156 	{10,  alien3_xpm, 50, t_diag, true,  true },
157 	{0,0,0,0,false,false}
158 };
159 const ConvoyData cd4[] = {
160 	{200, alien4_xpm,  50, u, false, true },
161 	{170, alien4_xpm,  50, u, false, true },
162 	{170, alien4_xpm,  50, u, false, true },
163 	{170, alien4_xpm,  50, u, false, true },
164 	{150, alien4_xpm,  30, v, false, false },
165 	{ 10, alien13_xpm, 15, v, false, false },
166 	{0,0,0,0,false,false}
167 };
168 const ConvoyData cd5[] = {
169 	{200, alien5_xpm, 50, loop,     false, false },
170 	{ 25, alien5_xpm, 50, loop,     true,  false },
171 	{150, alien5_xpm, 50, b_diag,   false, false },
172 	{150, alien5_xpm, 50, b_diag,   true,  false },
173 	{150, alien5_xpm, 50, loop,     false, false },
174 	{0,0,0,0,false,false}
175 };
176 const ConvoyData cd6[] = {
177 	{200, alien6_xpm,  50, hang,     false, true },
178 	{150, alien6_xpm,  50, infinity, false, true },
179 	{150, alien6_xpm,  50, infinity, true,  false },
180 	{100, alien6_xpm,  30, infinity, false, false },
181 	{100, alien6_xpm,  50, infinity, true,  false },
182 	{150, alien13_xpm, 15, b_diag,   true,  false },
183 	{0,0,0,0,false,false}
184 };
185 const ConvoyData cd7[] = {
186 	{200, alien7_xpm, 50, b_zz, false, true },
187 	{150, alien7_xpm, 50, t_zz, false, true },
188 	{100, alien7_xpm, 50, b_zz, false, true },
189 	{ 50, alien7_xpm, 50, t_zz, false, true },
190 	{ 10, alien7_xpm, 50, t_zz, false, true },
191 	{0,0,0,0,false,false}
192 };
193 const ConvoyData cd8[] = {
194 	{200, alien8_xpm, 50, sine,    false, false },
195 	{  0, alien8_xpm, 50, sine,    true,  true },
196 	{ 50, alien8_xpm, 25, drop128, false, true },
197 	{  5, alien8_xpm, 25, drop256, false, true },
198 	{  5, alien8_xpm, 25, drop384, false, true },
199 	{  5, alien8_xpm, 25, drop512, false, true },
200 	{  5, alien8_xpm, 25, drop640, false, true },
201 	{  5, alien8_xpm, 25, drop768, false, true },
202 	{0,0,0,0,false,false}
203 };
204 const ConvoyData cd9[] = {
205 	{200, alien9_xpm, 10, t_circ, false, false },
206 	{ 50, alien9_xpm, 20, t_circ, true,  false },
207 	{ 50, alien9_xpm, 30, t_circ, false, false },
208 	{ 50, alien9_xpm, 40, t_circ, true,  false },
209 	{ 50, alien9_xpm, 50, t_circ, false, true },
210 	{ 50, alien9_xpm, 50, t_circ, true,  true },
211 	{ 50, alien9_xpm, 40, t_circ, false, false },
212 	{ 50, alien9_xpm, 30, t_circ, true,  false },
213 	{ 50, alien9_xpm, 20, t_circ, false, false },
214 	{ 50, alien9_xpm, 10, t_circ, true,  false },
215 	{0,0,0,0,false,false}
216 };
217 const ConvoyData cd10[] = {
218 	{200, alien10_xpm, 50, boing, false, false },
219 	{50,  alien10_xpm, 50, boing, true,  false },
220 	{10,  alien10_xpm, 50, boing, false, true },
221 	{10,  alien10_xpm, 50, boing, false, true },
222 	{10,  alien10_xpm, 50, boing, false, true },
223 	{10,  alien10_xpm, 50, boing, false, true },
224 	{10,  alien10_xpm, 50, boing, false, true },
225 	{10,  alien10_xpm, 50, boing, false, true },
226 	{0,0,0,0,false,false}
227 };
228 const ConvoyData cd11[] = {
229 	{200, alien11_xpm, 50, sine, false, true },
230 	{25,  alien11_xpm, 50, sine, false, true },
231 	{25,  alien11_xpm, 50, sine, false, true },
232 	{25,  alien11_xpm, 50, sine, false, true },
233 	{0,0,0,0,false,false}
234 };
235 const ConvoyData cd12[] = {
236 	{200, alien12_xpm, 13, drop128, false, false },
237 	{0, alien12_xpm, 13, drop896, false, false },
238 	{0, alien12_xpm, 13, drop256, false, false },
239 	{0, alien12_xpm, 13, drop768, false, false },
240 	{0, alien12_xpm, 13, drop384, false, false },
241 	{0, alien12_xpm, 13, drop640, false, false },
242 	{0, alien13_xpm, 25, drop512, false, false },
243 	{0,0,0,0,false,false}
244 };
245 const ConvoyData cd13[] = {
246 	{100, alien14_xpm, 50, v, false, true },
247 	{0,   alien1_xpm,  50, v, false, true },
248 	{0,   alien2_xpm,  50, v, false, true },
249 	{0,   alien3_xpm,  50, v, false, true },
250 	{0,   alien4_xpm,  50, v, false, true },
251 	{0,   alien5_xpm,  50, v, false, true },
252 	{0,   alien6_xpm,  50, v, false, true },
253 	{0,   alien7_xpm,  50, v, false, true },
254 	{0,   alien8_xpm,  50, v, false, true },
255 	{0,   alien9_xpm,  50, v, false, true },
256 	{0,0,0,0,false,false}
257 };
258 
259 
260 // Game levels
261 const ConvoyData *const levels[] = {
262 	cd1, cd2, cd3, cd4, cd5, cd6, cd7, cd8, cd9, cd10, cd11, cd12, cd13
263 };
264 
265 } // namespace Data
266 
267 
268 
269 /*
270  *  Main functions
271  */
272 
NewLevel(BulletsManager * bombs_manager,BulletsManager * bullets_manager,BonusManager * bonus_manager,ExplosionsManager * explosions_manager)273 AliensManager * NewLevel(BulletsManager * bombs_manager,
274                          BulletsManager * bullets_manager,
275                          BonusManager * bonus_manager,
276                          ExplosionsManager * explosions_manager)
277 {
278 	const size_t nb_levels (sizeof Data::levels / sizeof Data::levels[0]);
279 	const size_t data_number ((Score::Instance().Level() - 1) % nb_levels);
280 	return new AliensManager (bombs_manager, bullets_manager,
281 	                          bonus_manager, explosions_manager,
282 	                          Score::Instance().Level(),
283 	                          Data::levels[data_number],
284 	                          nb_levels);
285 }
286 
287 
Play()288 void Play()
289 {
290 	X11::Inst().ClearWindow();
291 	Score::Instance().ReInit();
292 
293 	Input input;
294 	BulletsManager bullets, bombs;
295 	BonusManager bonuses;
296 	ExplosionsManager explosions;
297 	std::auto_ptr<AliensManager> aliens (NewLevel(&bombs, &bullets, &bonuses, &explosions));
298 	Player player (&bullets, &bombs, &bonuses, &explosions, Score::Instance().Height() + 1);
299 	Score::Instance().SetShield(player.Shield());
300 	int fast_star_scrolling_time (0);
301 	bool cheated (false);
302 	bool window_resized (false);
303 	bool rate_changed (false);
304 	Coord last_window_size (X11::Inst().WindowWidth(), X11::Inst().WindowHeight());
305 	double frame_time (0);
306 
307 	for (;;) {
308 		input.Update();
309 		if (input.Quit()) break;
310 		if (!input.Pause()) {
311 			Config::Instance().AddDetailsLevel(input.Details());
312 
313 			if (input.IncRefreshRate()) {
314 				Config::Instance().SetNextRefreshRate();
315 				rate_changed = true;
316 			}
317 
318 			SetStandardWindowSize(input.WindowSize());
319 			X11::Inst().GetWindowAttributes();
320 			if (last_window_size != Coord(X11::Inst().WindowWidth(), X11::Inst().WindowHeight())) {
321 				last_window_size = Coord(X11::Inst().WindowWidth(), X11::Inst().WindowHeight());
322 				window_resized = true;
323 			}
324 
325 			const int old_score (Score::Instance().Value());
326 			Score::Instance().Add(aliens->DoBulletsCollisions());
327 			if (old_score % 1000 > Score::Instance().Value() % 1000) {
328 				player.ExtraShield();
329 			}
330 			player.DoBombsCollisions();
331 			player.DoBonusCollisions();
332 			if (input.Cheat()) {
333 				cheated = true;
334 				player.ExtraFire();
335 				player.ExtraShield();
336 			}
337 
338 			Score::Instance().SetShield(player.Shield());
339 			if (player.Shield() < 0) {
340 				if (!cheated && !window_resized && !rate_changed) {
341 					HighScores::Instance().Add(Score::Instance().Value(), last_window_size, Config::Instance().RefreshRate());
342 				}
343 				break;
344 			}
345 
346 			if (aliens->Finished()) {
347 				Score::Instance().IncLevel();
348 				std::auto_ptr<AliensManager> n (NewLevel(&bombs, &bullets, &bonuses, &explosions));
349 				aliens = n;
350 				fast_star_scrolling_time = 100;
351 			}
352 
353 			StarsFields::Instance().Scroll();
354 			if (fast_star_scrolling_time > 0) {
355 				--fast_star_scrolling_time;
356 				if (fast_star_scrolling_time == 0) Score::Instance().EraseLevel();
357 				StarsFields::Instance().Scroll();
358 				StarsFields::Instance().Scroll();
359 				if (fast_star_scrolling_time > 0) Score::Instance().ShowLevel();
360 			}
361 
362 			aliens->Move();
363 			bonuses.Move();
364 			player.Move(input.Move());
365 			bullets.Move();
366 			bombs.Move();
367 			aliens->Fire();
368 			if (input.Fire()) player.Fire();
369 			explosions.Move();
370 			Score::Instance().Refresh();
371 		}
372 		X11::Inst().Sync(False);
373 		frame_time = SleepTimeInterval(frame_time, 1.0 / Config::Instance().RefreshRate());
374 	}
375 }
376 
377 
MainLoop()378 void MainLoop()
379 {
380 	X11::CreateInstance();
381 	X11::Inst().SetWindowTitle("XGalaga++");
382 	X11::Inst().SetInvisibleCursor();
383 	while (StartMenu::Instance().Display()) {
384 		Play();
385 	}
386 }
387 
388 
main()389 int main()
390 {
391 	int code (0);
392 	try {
393 		MainLoop();
394 	}
395 	catch (const std::exception & e) {
396 		std::cerr << e.what() << std::endl;
397 		code = 1;
398 	}
399 	catch (...) {
400 		std::cerr << "Unknown exception." << std::endl;
401 		code = 1;
402 	}
403 	InstancesManager::DestroyInstance();
404 	return code;
405 }
406