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