1 #include <stdlib.h>
2 #include <stdio.h>
3 #ifdef __EMSCRIPTEN__
4 #include <emscripten/emscripten.h>
5 #endif
6 #include <SDL.h>
7 #include <time.h>
8 #include <unistd.h>
9 #include <getopt.h>
10 #include "mrboom.h"
11 #include "common.hpp"
12 #include "MrboomHelper.hpp"
13 #include "xbrz.h"
14
15 #define IFTRACES (traceMask & DEBUG_SDL2)
16
17 #ifdef DEBUG
18 #define XBRZ_DEFAULT_FACTOR 1
19 #else
20 #define XBRZ_DEFAULT_FACTOR 2
21 #endif
22 #ifdef __ARM_ARCH_6__
23 #define XBRZ_DEFAULT_FACTOR 1
24 #endif
25 #ifdef __ARM_ARCH_7__
26 #define XBRZ_DEFAULT_FACTOR 1
27 #endif
28
29 int xbrzFactor = XBRZ_DEFAULT_FACTOR;
30 int widthTexture = 0;
31 int heightTexture = 0;
32
33 #define BEEING_PLAYING_BUFFER 60
34 int beeingPlaying = 0;
35
36 SDL_Renderer *renderer;
37 SDL_Texture * texture;
38 SDL_bool done = SDL_FALSE;
39 SDL_bool noVGA = SDL_FALSE;
40
41 SDL_Joystick *joysticks[nb_dyna] = { 0 };
42 int joysticksInstance[nb_dyna];
43
44 static clock_t begin;
45 unsigned int nbFrames = 0;
46 int testAI = 0;
47 bool slowMode = false;
48 #define MAX_TURBO 32
49 int turboMode = 0;
50 int anyButtonPushedMask = 0;
51 int anyStartButtonPushedMask = 0;
52 int anySelectButtonPushedMask = 0;
53 int framesPlayed = 0;
54 bool checkDemoMode = false;
55
quit(int rc)56 void quit(int rc)
57 {
58 SDL_Quit();
59 exit(rc);
60 }
61
printJoystick()62 void printJoystick()
63 {
64 int i;
65
66 for (i = 0; i < nb_dyna; i++)
67 {
68 if (joysticks[i] != 0)
69 {
70 log_debug("Joystick instance %d: (index:%d)\n", joysticksInstance[i], i);
71 }
72 }
73 }
74
removeJoystick(int instance)75 void removeJoystick(int instance)
76 {
77 int i;
78
79 if (IFTRACES)
80 {
81 log_debug("Joystick instance %d removed.\n", (int)instance);
82 }
83 for (i = 0; i < nb_dyna; i++)
84 {
85 if (joysticks[i] != 0)
86 {
87 if (joysticksInstance[i] == instance)
88 {
89 joysticks[i] = 0;
90 if (IFTRACES)
91 {
92 log_debug("Joystick index/player %d removed.\n", i);
93 }
94 }
95 }
96 }
97 }
98
updateInput(int keyid,int playerNumber,int state,bool isIA)99 void updateInput(int keyid, int playerNumber, int state, bool isIA) {
100 if (!checkDemoMode) {
101 mrboom_update_input(keyid, playerNumber, state, isIA);
102 }
103 }
104
105
addJoystick(int index)106 void addJoystick(int index)
107 {
108 if (IFTRACES)
109 {
110 log_debug("Add Joystick index %d \n", index);
111 }
112 SDL_Joystick *joystick = SDL_JoystickOpen(index);
113 if (joystick == NULL)
114 {
115 log_error("SDL_JoystickOpen(%d) failed: %s\n", index,
116 SDL_GetError());
117 }
118 else
119 {
120 int noFreePlayer = 1;
121 for (int i = 0; i < nb_dyna; i++)
122 {
123 if (joysticks[i] == 0)
124 {
125 joysticks[i] = joystick;
126 joysticksInstance[i] = SDL_JoystickInstanceID(joystick);
127 if (IFTRACES)
128 {
129 log_debug("Joystick instance %d added for player %d\n", joysticksInstance[i], i);
130 }
131 noFreePlayer = 0;
132 return;
133 }
134 }
135
136 if (noFreePlayer)
137 {
138 if (IFTRACES)
139 {
140 log_debug("Joystick cant be added\n");
141 }
142 }
143 }
144 }
145
146 #define NB_SCREENS_BLURRING 8
147
UpdateTexture(SDL_Texture * texture,bool skipRendering)148 void UpdateTexture(SDL_Texture *texture, bool skipRendering)
149 {
150 static uint32_t matrixPalette[NB_COLORS_PALETTE];
151 static uint32_t previousScreen[WIDTH][HEIGHT][NB_SCREENS_BLURRING];
152 static int numberOfScreenToMelt = 1;
153
154 Uint32 * dst;
155 uint32_t src[WIDTH * HEIGHT];
156 static uint32_t *trg = NULL;
157
158 if (trg == NULL)
159 {
160 trg = (uint32_t *)malloc(widthTexture * heightTexture * sizeof(uint32_t));
161 }
162 int row, col;
163 void *pixels;
164 int pitch;
165
166 if (SDL_LockTexture(texture, NULL, &pixels, &pitch) < 0)
167 {
168 log_error("Couldn't lock texture: %s\n", SDL_GetError());
169 quit(5);
170 }
171 int z = 0;
172 do
173 {
174 matrixPalette[z / 3] = ((m.vgaPalette[z+0] << 2) | (m.vgaPalette[z+0] >> 4)) << 16;
175 matrixPalette[z / 3] |= ((m.vgaPalette[z+1] << 2) | (m.vgaPalette[z+1] >> 4)) << 8;
176 matrixPalette[z / 3] |= ((m.vgaPalette[z+2] << 2) | (m.vgaPalette[z+2] >> 4)) << 0;
177 z += 3;
178 } while (z != NB_COLORS_PALETTE * 3);
179
180 for (row = 0; row < HEIGHT; ++row)
181 {
182 dst = (Uint32 *)((Uint8 *)pixels + row * pitch);
183 for (col = 0; col < WIDTH; ++col)
184 {
185 uint32_t color;
186 if (m.affiche_pal != 1)
187 {
188 color = matrixPalette[m.buffer[col + row * WIDTH]];
189 m.vgaRam[col + row * WIDTH] = m.buffer[col + row * WIDTH];
190 }
191 else
192 {
193 color = matrixPalette[m.vgaRam[col + row * WIDTH]];
194 }
195 previousScreen[col][row][frameNumber() % NB_SCREENS_BLURRING] = color;
196 //uint32_t color = matrixPalette[m.vgaRam[col + row * WIDTH]];
197 //previousScreen[col][row][frameNumber() % NB_SCREENS_BLURRING] = color;
198 if (skipRendering)
199 {
200 uint32_t b = 0;
201 uint32_t r = 0;
202 uint32_t g = 0;
203 for (int z = 0; z < numberOfScreenToMelt; z++)
204 {
205 uint32_t prevColor = previousScreen[col][row][(NB_SCREENS_BLURRING - z + frameNumber()) % NB_SCREENS_BLURRING];
206 b += prevColor & 255;
207 r += (prevColor >> 8) & 255;
208 g += (prevColor >> 16) & 255;
209 }
210 b = b / (numberOfScreenToMelt);
211 r = r / (numberOfScreenToMelt);
212 g = g / (numberOfScreenToMelt);
213 color = (g << 16) | (r << 8) | b;
214 if (numberOfScreenToMelt < NB_SCREENS_BLURRING - 1)
215 {
216 numberOfScreenToMelt += 2;
217 }
218 }
219 else
220 {
221 numberOfScreenToMelt = 1;
222 }
223 if (xbrzFactor != 1)
224 {
225 src[col + row * WIDTH] = color;
226 }
227 else
228 {
229 *dst++ = color;
230 }
231 }
232 }
233
234 if (xbrzFactor != 1)
235 {
236 scale(xbrzFactor, //valid range: 2 - 6
237 (uint32_t *)src, trg, WIDTH, HEIGHT,
238 xbrz::ColorFormat::RGB);
239
240 for (row = 0; row < heightTexture; ++row)
241 {
242 dst = (Uint32 *)((Uint8 *)pixels + row * pitch);
243 for (col = 0; col < widthTexture; ++col)
244 {
245 *dst++ = trg[row * widthTexture + col];
246 }
247 }
248 }
249
250 SDL_UnlockTexture(texture);
251 }
252
getPlayerFromJoystickPort(int instance)253 int getPlayerFromJoystickPort(int instance)
254 {
255 int i;
256
257 for (i = 0; i < nb_dyna; i++)
258 {
259 if (joysticks[i] != 0)
260 {
261 if (joysticksInstance[i] == instance)
262 {
263 return(i);
264 }
265 }
266 }
267 log_error("Error getPlayerFromJoystickPort %d\n", instance);
268 return(0);
269 }
270
updateKeyboard(Uint8 scancode,int state)271 void updateKeyboard(Uint8 scancode, int state)
272 {
273 if (IFTRACES)
274 {
275 log_debug("updateKeyboard %d", scancode);
276 }
277 if (state)
278 {
279 anyButtonPushedMask = anyButtonPushedMask | (1 << (scancode & 31));
280 }
281 else
282 {
283 anyButtonPushedMask = anyButtonPushedMask & ~(1 << (scancode & 31));
284 }
285 switch (scancode)
286 {
287 case SDL_SCANCODE_W:
288 updateInput(button_up, nb_dyna - 2, state, false);
289 break;
290
291 case SDL_SCANCODE_S:
292 updateInput(button_down, nb_dyna - 2, state, false);
293 break;
294
295 case SDL_SCANCODE_A:
296 updateInput(button_left, nb_dyna - 2, state, false);
297 break;
298
299 case SDL_SCANCODE_D:
300 updateInput(button_right, nb_dyna - 2, state, false);
301 break;
302
303 case SDL_SCANCODE_LALT:
304 updateInput(button_a, nb_dyna - 2, state, false);
305 break;
306
307 case SDL_SCANCODE_LCTRL:
308 case SDL_SCANCODE_LGUI:
309 updateInput(button_b, nb_dyna - 2, state, false);
310 break;
311
312 case SDL_SCANCODE_LSHIFT:
313 updateInput(button_x, nb_dyna - 2, state, false);
314 break;
315
316 case SDL_SCANCODE_SPACE:
317 updateInput(button_select, nb_dyna - 2, state, false);
318 break;
319
320 case SDL_SCANCODE_RETURN:
321 updateInput(button_start, nb_dyna - 2, state, false);
322 updateInput(button_start, nb_dyna - 1, state, false);
323 break;
324
325 case SDL_SCANCODE_KP_ENTER:
326 updateInput(button_start, nb_dyna - 2, state, false);
327 updateInput(button_start, nb_dyna - 1, state, false);
328 updateInput(button_x, nb_dyna - 1, state, false); // also jump 1st player
329 break;
330
331 case SDL_SCANCODE_UP:
332 updateInput(button_up, nb_dyna - 1, state, false);
333 break;
334
335 case SDL_SCANCODE_DOWN:
336 updateInput(button_down, nb_dyna - 1, state, false);
337 break;
338
339 case SDL_SCANCODE_LEFT:
340 updateInput(button_left, nb_dyna - 1, state, false);
341 break;
342
343 case SDL_SCANCODE_RIGHT:
344 updateInput(button_right, nb_dyna - 1, state, false);
345 break;
346 case SDL_SCANCODE_F1:
347 updateInput(button_l, nb_dyna - 1, state, false);
348 break;
349 case SDL_SCANCODE_F2:
350 updateInput(button_r, nb_dyna - 1, state, false);
351 break;
352 case SDL_SCANCODE_PAGEDOWN:
353 case SDL_SCANCODE_RALT:
354 case SDL_SCANCODE_KP_PERIOD:
355 updateInput(button_a, nb_dyna - 1, state, false);
356 break;
357
358 case SDL_SCANCODE_END:
359 case SDL_SCANCODE_RCTRL:
360 case SDL_SCANCODE_RGUI:
361 case SDL_SCANCODE_KP_0:
362 log_debug("button_b %d i:%d\n", state, nb_dyna - 1);
363 updateInput(button_b, nb_dyna - 1, state, false);
364 break;
365
366 case SDL_SCANCODE_HOME:
367 case SDL_SCANCODE_RSHIFT:
368 updateInput(button_x, nb_dyna - 1, state, false);
369 break;
370
371 case SDL_SCANCODE_ESCAPE:
372 if (state)
373 {
374 if ((beeingPlaying > BEEING_PLAYING_BUFFER) || !isGameActive())
375 {
376 pressESC();
377 }
378 if (inTheMenu())
379 {
380 done = SDL_TRUE;
381 }
382 }
383 break;
384
385 case SDL_SCANCODE_PAUSE:
386 case SDL_SCANCODE_P:
387 if (state)
388 {
389 pauseGameButton();
390 }
391 break;
392
393 default:
394 if (IFTRACES)
395 {
396 log_debug("updateKeyboard not handled %d %d\n", scancode, state);
397 }
398 break;
399 }
400 }
401
402 #define DEFAULT_DEAD_ZONE 8000
403
404 int joystickDeadZone = DEFAULT_DEAD_ZONE;
405 int anyStartButtonPushedCounter = 0;
406 uint32_t windowID;
407 static const float ASPECT_RATIO = float(WIDTH) / float(HEIGHT);
408
409
410 bool resizeDone = false;
411 SDL_Rect screen;
412 SDL_Window *window;
413 int width = 0;
414 int height = 0;
415
416 #define NB_STICKS_MAX_PER_PAD 2
417
418 int axis[NB_STICKS_MAX_PER_PAD * 2] = { 0, 0, 0, 0 };
419
420
pollEvent()421 void pollEvent() {
422 SDL_Event e;
423
424 while (SDL_PollEvent(&e))
425 {
426 switch (e.type)
427 {
428 case SDL_WINDOWEVENT:
429 if (e.window.windowID == windowID)
430 {
431 switch (e.window.event)
432 {
433 case SDL_WINDOWEVENT_RESIZED: {
434 width = e.window.data1;
435 height = e.window.data2;
436 float aspectRatio = (float)width / (float)height;
437 if (abs(aspectRatio - ASPECT_RATIO) > 0.1)
438 {
439 if (aspectRatio < ASPECT_RATIO)
440 {
441 height = (1.f / ASPECT_RATIO) * width;
442 }
443 else
444 {
445 width = ASPECT_RATIO * height;
446 }
447 log_debug("Setting window size to %d, %d, aspect ratio: %f\n",
448 width, height, (float)width / (float)height);
449 }
450 else
451 {
452 log_debug("skip resize %f %f\n", aspectRatio, ASPECT_RATIO);
453 break;
454 }
455 screen.w = width;
456 screen.h = height;
457 resizeDone = true;
458 break;
459 }
460 }
461 }
462 break;
463
464 case SDL_JOYDEVICEADDED:
465 addJoystick(e.jdevice.which);
466 break;
467
468 case SDL_JOYDEVICEREMOVED:
469 removeJoystick(e.jdevice.which);
470 break;
471
472 case SDL_JOYAXISMOTION:
473
474 if (e.jaxis.axis >= NB_STICKS_MAX_PER_PAD * 2)
475 {
476 if (IFTRACES)
477 {
478 log_debug("ignoring e.jaxis.axis=%d e.jaxis.value=%d player=%d\n", e.jaxis.axis, e.jaxis.value, getPlayerFromJoystickPort(e.jaxis.which));
479 }
480 break;
481 }
482
483 if (e.jaxis.value < -joystickDeadZone)
484 {
485 axis[e.jaxis.axis] = -1;
486 }
487 else if (e.jaxis.value > joystickDeadZone)
488 {
489 axis[e.jaxis.axis] = 1;
490 }
491 else
492 {
493 axis[e.jaxis.axis] = 0;
494 }
495
496 if (IFTRACES)
497 {
498 log_debug("e.jaxis.axis=%d e.jaxis.value=%d player=%d\n", e.jaxis.axis, e.jaxis.value, getPlayerFromJoystickPort(e.jaxis.which));
499 }
500 if ((e.jaxis.axis == 0) || (e.jaxis.axis == 2))
501 {
502 if ((axis[0] == 1) || (axis[2] == 1))
503 {
504 updateInput(button_right, getPlayerFromJoystickPort(e.jaxis.which), 1, false);
505 updateInput(button_left, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
506 }
507 else if ((axis[0] == -1) || (axis[2] == -1))
508 {
509 updateInput(button_left, getPlayerFromJoystickPort(e.jaxis.which), 1, false);
510 updateInput(button_right, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
511 }
512 else
513 {
514 updateInput(button_left, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
515 updateInput(button_right, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
516 }
517 }
518 if ((e.jaxis.axis == 1) || (e.jaxis.axis == 3))
519 {
520 if ((axis[1] == 1) || (axis[3] == 1))
521 {
522 updateInput(button_down, getPlayerFromJoystickPort(e.jaxis.which), 1, false);
523 updateInput(button_up, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
524 }
525 else if ((axis[1] == -1) || (axis[3] == -1))
526 {
527 updateInput(button_up, getPlayerFromJoystickPort(e.jaxis.which), 1, false);
528 updateInput(button_down, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
529 }
530 else
531 {
532 updateInput(button_up, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
533 updateInput(button_down, getPlayerFromJoystickPort(e.jaxis.which), 0, false);
534 }
535 }
536 break;
537
538 case SDL_JOYHATMOTION:
539 {
540 int player = getPlayerFromJoystickPort(e.jhat.which);
541 if (IFTRACES)
542 {
543 log_debug("SDL_JOYHATMOTION: .jhat=%d which=%d player=%d\n", e.jhat.value, e.jhat.which, getPlayerFromJoystickPort(e.jhat.which));
544 }
545
546 switch (e.jhat.value)
547 {
548 case SDL_HAT_CENTERED:
549 updateInput(button_up, player, 0, false);
550 updateInput(button_down, player, 0, false);
551 updateInput(button_left, player, 0, false);
552 updateInput(button_right, player, 0, false);
553 break;
554
555 case SDL_HAT_UP:
556 updateInput(button_up, player, 1, false);
557 updateInput(button_down, player, 0, false);
558 updateInput(button_left, player, 0, false);
559 updateInput(button_right, player, 0, false);
560 break;
561
562 case SDL_HAT_DOWN:
563 updateInput(button_up, player, 0, false);
564 updateInput(button_down, player, 1, false);
565 updateInput(button_left, player, 0, false);
566 updateInput(button_right, player, 0, false);
567 break;
568
569 case SDL_HAT_LEFT:
570 updateInput(button_up, player, 0, false);
571 updateInput(button_down, player, 0, false);
572 updateInput(button_left, player, 1, false);
573 updateInput(button_right, player, 0, false);
574 break;
575
576 case SDL_HAT_RIGHT:
577 updateInput(button_up, player, 0, false);
578 updateInput(button_down, player, 0, false);
579 updateInput(button_left, player, 0, false);
580 updateInput(button_right, player, 1, false);
581 break;
582
583 case SDL_HAT_RIGHTDOWN:
584 updateInput(button_up, player, 0, false);
585 updateInput(button_down, player, 1, false);
586 updateInput(button_left, player, 0, false);
587 updateInput(button_right, player, 1, false);
588 break;
589
590 case SDL_HAT_RIGHTUP:
591 updateInput(button_up, player, 1, false);
592 updateInput(button_down, player, 0, false);
593 updateInput(button_left, player, 0, false);
594 updateInput(button_right, player, 1, false);
595 break;
596
597 case SDL_HAT_LEFTUP:
598 updateInput(button_up, player, 1, false);
599 updateInput(button_down, player, 0, false);
600 updateInput(button_left, player, 1, false);
601 updateInput(button_right, player, 0, false);
602 break;
603
604 case SDL_HAT_LEFTDOWN:
605 updateInput(button_up, player, 0, false);
606 updateInput(button_down, player, 1, false);
607 updateInput(button_left, player, 1, false);
608 updateInput(button_right, player, 0, false);
609 break;
610 }
611 }
612 break;
613
614 case SDL_JOYBUTTONDOWN:
615 if (IFTRACES)
616 {
617 log_debug("Joystick %d button %d down\n",
618 e.jbutton.which, e.jbutton.button);
619 }
620 switch (e.jbutton.button)
621 {
622 case 0:
623 updateInput(button_a, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
624 break;
625
626 case 1:
627 updateInput(button_b, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
628 break;
629
630 case 2:
631 updateInput(button_x, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
632 break;
633
634 case 3:
635 updateInput(button_y, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
636 break;
637
638 case 4:
639 updateInput(button_l, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
640 break;
641
642 case 5:
643 updateInput(button_r, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
644 break;
645
646 case 6:
647 case 8:
648 updateInput(button_select, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
649 anySelectButtonPushedMask = anySelectButtonPushedMask | (1 << e.jbutton.which);
650 break;
651
652 case 7:
653 case 9:
654 updateInput(button_start, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
655 anyStartButtonPushedMask = anyStartButtonPushedMask | (1 << e.jbutton.which);
656 break;
657
658 case 10:
659 updateInput(button_up, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
660 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
661 break;
662
663 case 11:
664 updateInput(button_down, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
665 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
666 break;
667
668 case 12:
669 updateInput(button_left, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
670 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
671 break;
672
673 case 13:
674 updateInput(button_right, getPlayerFromJoystickPort(e.jbutton.which), 1, false);
675 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
676 break;
677 }
678 anyButtonPushedMask = anyButtonPushedMask | (1 << e.jbutton.button);
679 break;
680
681 case SDL_JOYBUTTONUP:
682 if (IFTRACES)
683 {
684 log_debug("Joystick %d button %d up\n",
685 e.jbutton.which, e.jbutton.button);
686 }
687 switch (e.jbutton.button)
688 {
689 case 0:
690 updateInput(button_a, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
691 break;
692
693 case 1:
694 updateInput(button_b, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
695 break;
696
697 case 2:
698 updateInput(button_x, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
699 break;
700
701 case 3:
702 updateInput(button_y, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
703 break;
704
705 case 4:
706 updateInput(button_l, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
707 break;
708
709 case 5:
710 updateInput(button_r, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
711 break;
712
713 case 6:
714 case 8:
715 updateInput(button_select, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
716 anySelectButtonPushedMask = anySelectButtonPushedMask & ~(1 << e.jbutton.which);
717 break;
718
719 case 7:
720 case 9:
721 updateInput(button_start, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
722 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
723 break;
724
725 case 10:
726 updateInput(button_up, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
727 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
728 break;
729
730 case 11:
731 updateInput(button_down, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
732 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
733 break;
734
735 case 12:
736 updateInput(button_left, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
737 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
738 break;
739
740 case 13:
741 updateInput(button_right, getPlayerFromJoystickPort(e.jbutton.which), 0, false);
742 anyStartButtonPushedMask = anyStartButtonPushedMask & ~(1 << e.jbutton.which);
743 break;
744 }
745 anyButtonPushedMask = anyButtonPushedMask & ~(1 << e.jbutton.button);
746 break;
747
748 case SDL_KEYDOWN:
749 updateKeyboard(e.key.keysym.scancode, 1);
750 break;
751
752 case SDL_KEYUP:
753 updateKeyboard(e.key.keysym.scancode, 0);
754 break;
755
756 case SDL_FINGERDOWN:
757 case SDL_MOUSEBUTTONDOWN:
758 break;
759
760 case SDL_QUIT:
761 done = SDL_TRUE;
762 break;
763
764 default:
765 break;
766 }
767 }
768 }
769 void
loop()770 loop()
771 {
772
773 if (isGameActive())
774 {
775 beeingPlaying++;
776 if (beeingPlaying > BEEING_PLAYING_BUFFER)
777 {
778 if (anyStartButtonPushedMask && anySelectButtonPushedMask)
779 {
780 pressESC();
781 }
782 else
783 {
784 if (anyStartButtonPushedMask)
785 {
786 anyStartButtonPushedCounter++;
787 if (anyStartButtonPushedCounter == 1)
788 {
789 pauseGameButton();
790 }
791 }
792 else
793 {
794 anyStartButtonPushedCounter = 0;
795 }
796 }
797 }
798 }
799 else
800 {
801 beeingPlaying = 0;
802 }
803
804 if (checkDemoMode) {
805 static int zz = 0;
806 static int frameResult[16] = {
807 195663,60551,77663,53283,45147,79144,75015,149583,65639,142559,182999,132883,172439,123599,202267,112111
808 };
809 static bool isActive = false;
810 bool currentActive = !inTheMenu();
811
812 if (!currentActive && isActive) {
813 int fn = frameNumber();
814 if (frameResult[zz] != fn) {
815 log_error("Failed check on demo %d\n", zz+1);
816 exit(1);
817 } else {
818 log_info("Checked demo %d/16 %d:OK\n", zz+1, fn);
819 }
820 zz++;
821 if ( zz == 16 ) {
822 log_info("SUCCESS check demos\n");
823 exit(0);
824 }
825 }
826 isActive = currentActive;
827 turboMode = MAX_TURBO;
828 }
829
830 pollEvent();
831
832
833 mrboom_deal_with_autofire();
834 mrboom_loop();
835
836 #ifdef DEBUG
837 if (mrboom_debug_state_failed())
838 {
839 log_error("mrboom_debug_state_failed!\n");
840 exit(1);
841 }
842 #endif
843
844 if (m.executionFinished)
845 {
846 done = SDL_TRUE;
847 }
848
849 mrboom_sound();
850
851 bool skipRendering = false;
852 static bool showFrame[MAX_TURBO][MAX_TURBO];
853 static bool calculateShowFrame = true;
854 int counter = 0;
855
856 #define INT_SCALING 100000
857 if (calculateShowFrame)
858 {
859 for (int i = 0; i < MAX_TURBO; i++)
860 {
861 int delta = ((MAX_TURBO - i) * INT_SCALING) / MAX_TURBO; // between 100 and 0
862 for (int j = 0; j < MAX_TURBO; j++)
863 {
864 counter += delta;
865 if (counter >= INT_SCALING)
866 {
867 counter -= INT_SCALING;
868 showFrame[i][j] = true;
869 }
870 else
871 {
872 showFrame[i][j] = false;
873 }
874 }
875 }
876 calculateShowFrame = false;
877 }
878
879 static int anyButtonPushedMaskSave = 0;
880 bool goTurbo = false;
881 if (!anyButtonPushedMask)
882 {
883 anyButtonPushedMaskSave = 0;
884 }
885 if (someHumanPlayersNotDead())
886 {
887 anyButtonPushedMaskSave = anyButtonPushedMask;
888 }
889 else
890 {
891 if (!isAboutToWin() && isGameActive())
892 {
893 if (anyButtonPushedMaskSave != anyButtonPushedMask) // to avoid speeding straight away when still holding current keys
894 {
895 goTurbo = true;
896 }
897 }
898 }
899 if (goTurbo)
900 {
901 if (!turboMode)
902 {
903 turboMode = 1;
904 }
905 if (!(frameNumber() % 32) && (turboMode < MAX_TURBO / 2))
906 {
907 turboMode++;
908 }
909 }
910 else
911 {
912 if (!(frameNumber() % 32) && (turboMode))
913 {
914 turboMode--;
915 }
916 }
917
918 int phaseShowFrame = turboMode ? turboMode + MAX_TURBO / 2 : 0;
919 if (phaseShowFrame > MAX_TURBO - 1)
920 {
921 phaseShowFrame = MAX_TURBO - 1;
922 }
923 if (showFrame[phaseShowFrame][frameNumber() % MAX_TURBO])
924 {
925 skipRendering = false;
926 }
927 else
928 {
929 skipRendering = true;
930 }
931 static bool previousSkipRendering = false;
932
933 if ((isGameActive() == false) || isGamePaused())
934 {
935 previousSkipRendering = false;
936 turboMode = 0;
937 }
938 if (noVGA == SDL_FALSE)
939 {
940 UpdateTexture(texture, previousSkipRendering);
941 previousSkipRendering = skipRendering;
942 }
943 if ((noVGA == SDL_FALSE) && skipRendering == false)
944 {
945 SDL_RenderClear(renderer);
946 SDL_RenderCopy(renderer, texture, NULL, NULL);
947 SDL_RenderPresent(renderer);
948 }
949
950 #ifdef __EMSCRIPTEN__
951 if (done)
952 {
953 emscripten_cancel_main_loop();
954 }
955 #endif
956 }
957
fps()958 static void fps()
959 {
960 nbFrames++;
961 if (!(nbFrames % 600) && (IFTRACES))
962 {
963 clock_t end = clock();
964 double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
965 log_debug("x time_spent=%f %d\n", time_spent, nbFrames);
966 log_debug("x fps=%f\n", nbFrames / time_spent);
967 }
968 }
969
printKeys()970 void printKeys()
971 {
972 log_info("Keys Space - Add a bomberman bot\n");
973 log_info(" Return - Start a game\n");
974 log_info(" P or Pause/Break - Pause\n");
975 log_info(" ESC - Quit\n");
976 log_info("1st player\n");
977 log_info(" Left - Left\n");
978 log_info(" Right - Right\n");
979 log_info(" Up - Up\n");
980 log_info(" Down - Down\n");
981 #ifdef __APPLE__
982 log_info(" Right Ctrl, End, Keypad 0 or Right Command - Lay bomb\n");
983 #else
984 log_info(" Right Ctrl, End, Keypad 0 or Right GUI - Lay bomb\n");
985 #endif
986 log_info(" Right Alt, Keypad Dot or PageDown - Ignite bomb\n");
987 log_info(" Right Shift, Keypad Enter or Home - Jump\n");
988 log_info("2nd player\n");
989 log_info(" A - Left\n");
990 log_info(" D - Right\n");
991 log_info(" W - Up\n");
992 log_info(" S - Down\n");
993 #ifdef __APPLE__
994 log_info(" Left Ctrl or Left Command - Lay bomb\n");
995 #else
996 log_info(" Left Ctrl or Left GUI - Lay bomb\n");
997 #endif
998 log_info(" Left Alt - Ignite bomb\n");
999 log_info(" Left Shift - Jump\n\n");
1000 log_info("run with -h to list options\n");
1001 }
1002
manageTestAI()1003 void manageTestAI()
1004 {
1005 static bool doItOnce = true;
1006 static bool doItOnce2 = true;
1007
1008 if (isGameActive() == false)
1009 {
1010 if (numberOfPlayers() != testAI)
1011 {
1012 addOneAIPlayer();
1013 }
1014 else
1015 {
1016 if (doItOnce)
1017 {
1018 pressStart();
1019 doItOnce = false;
1020 }
1021 }
1022 }
1023 else
1024 {
1025 if (cheatMode && doItOnce2)
1026 {
1027 activeCheatMode();
1028 doItOnce2 = false;
1029 }
1030 }
1031 }
1032
1033 int exitAtFrameNumber = 0;
1034 bool exitAtFrame = false;
1035 int
main(int argc,char ** argv)1036 main(int argc, char **argv)
1037 {
1038 bool showVersion = false;
1039 int c;
1040
1041 while (1)
1042 {
1043 static struct option long_options[] =
1044 {
1045 { "fx", required_argument, 0, 'f' },
1046 { "help", no_argument, 0, 'h' },
1047 { "level", required_argument, 0, 'l' },
1048 { "nomonster", no_argument, 0, 'm' },
1049 { "sex", no_argument, 0, 's' },
1050 { "color", no_argument, 0, 'c' },
1051 { "noautofire", no_argument, 0, 'n' },
1052 { "version", no_argument, 0, 'v' },
1053 { "debugtraces", required_argument, 0, 'd' },
1054 { "cheat", no_argument, 0, '1' },
1055 { "slow", no_argument, 0, '2' },
1056 { "frame", required_argument, 0, '3' },
1057 { "exit", required_argument, 0, '4' },
1058 { "tracemask", required_argument, 0, 't' },
1059 { "aitest", required_argument, 0, 'a' },
1060 { "nomusic", no_argument, 0, 'z' },
1061 { "xbrz", required_argument, 0, 'x' },
1062 { "skynet", no_argument, 0, 'k' },
1063 { "deadzone", required_argument, 0, 'd' },
1064 { "checkDemoMode", no_argument, 0, 'e' },
1065 { 0, 0, 0, 0 }
1066 };
1067 /* getopt_long stores the option index here. */
1068 int option_index = 0;
1069
1070 c = getopt_long(argc, argv, "hl:mscv123:4:t:f:o:a:nzx:kd:e",
1071 long_options, &option_index);
1072
1073 /* Detect the end of the options. */
1074 if (c == -1)
1075 {
1076 break;
1077 }
1078 switch (c)
1079 {
1080 case 'h':
1081 log_info("Usage: mrboom [options]\n");
1082 log_info("Options:\n");
1083 log_info(" -f <x>, --fx <x>\t\tFX volume: from 0 to 10\n");
1084 log_info(" -h, --help \t\tShow summary of options\n");
1085 log_info(" -l <x>, --level <x>\t\tStart in level 0:Candy 1:Pinguine 2:Pink\n");
1086 log_info(" \t\t3:Jungle 4:Board 5:Soccer 6:Sky 7:Aliens\n");
1087 log_info(" -m, --nomonster\t\tNo monster mode\n");
1088 log_info(" -s, --sex \t\tSex team mode\n");
1089 log_info(" -c, --color \t\tColor team mode\n");
1090 log_info(" -k, --skynet \t\tHumans vs. machines mode\n");
1091 // log_info(" -n, --noautofire \t\tNo autofire for bomb drop\n");
1092 log_info(" -d <x>, --deadzone <x>\tSet joysticks dead zone, default is %d\n", DEFAULT_DEAD_ZONE);
1093 log_info(" -z, --nomusic \t\tNo music\n");
1094 log_info(" -v, --version \t\tDisplay version\n");
1095 #ifdef DEBUG
1096 log_info("Debugging options:\n");
1097 log_info(" -x <x>, --xbrz <x>\t\tSet xBRZ shader factor: from 1 to 6 (default is %d, 1 is off)\n", XBRZ_DEFAULT_FACTOR);
1098 log_info(" -o <x>, --output <x>\t\tDebug traces to <x> file\n");
1099 log_info(" -t <x>, --tracemask <x>\tDebug traces mask <x>:\n");
1100 log_info(" \t\t1 to 128 player selection bit\n");
1101 log_info(" \t\t256 Grids\n");
1102 log_info(" \t\t512 Bot tree decisions\n");
1103 log_info(" \t\t1024 SDL2 stuff\n");
1104
1105 for (int i = 0; i < nb_dyna; i++)
1106 {
1107 const char *desc[nb_dyna] = { "white male", "white female", "red male", "red female", "blue male", "blue female", "green male", "green female" };
1108
1109 log_info(" \t\t%d all traces %s (#%d)\n", 256 + 512 + (1 << i), desc[i], i);
1110 }
1111
1112 log_info(" -1, --cheat \t\tActivate F1/F2 and L1/L2 pad key for debugging\n");
1113 log_info(" -2, --slow \t\tSlow motion for AI debugging\n");
1114 log_info(" -3 <x>, --frame <x> \tSet frame for randomness debugging\n");
1115 log_info(" -4 <x>, --exit <x> \tExit at frame <x> use x = -1 to exit after one game\n");
1116 log_info(" -a <x>, --aitest <x> \tTest <x> AI players\n");
1117 #endif
1118 exit(0);
1119 break;
1120
1121 case 't':
1122 traceMask = atoi(optarg);
1123 log_info("-t option given. Set tracemask to %d.\n", traceMask);
1124 break;
1125
1126 case 'f':
1127 sdl2_fx_volume = atoi(optarg);
1128 if ((sdl2_fx_volume < 0) || (sdl2_fx_volume > 10))
1129 {
1130 sdl2_fx_volume = DEFAULT_SDL2_FX_VOLUME;
1131 }
1132 log_info("-f option given. Set fx volume to %d.\n", sdl2_fx_volume);
1133 break;
1134
1135 case 'n':
1136 log_info("-n option given. No autofire\n");
1137 setAutofire(false);
1138 break;
1139
1140 case 'v':
1141 log_info("%s %s\n", GAME_NAME, GAME_VERSION);
1142 showVersion = true;
1143 break;
1144
1145 case 'l':
1146 #define NB_LEVELS 8
1147 log_info("-l option given. choosing level %s.\n", optarg);
1148 chooseLevel(atoi(optarg) % NB_LEVELS);
1149 break;
1150
1151 case 'm':
1152 log_info("-m option given. No monster mode.\n");
1153 setNoMonsterMode(true);
1154 break;
1155
1156 case 'o':
1157 log_info("logging to file %s\n", optarg);
1158 logDebug = fopen(optarg, "w");
1159 break;
1160
1161 case '1':
1162 log_info("-1 option given. Activate F1/F2 and L1/L2 pad key for debugging.\n");
1163 cheatMode = true;
1164 break;
1165
1166 case '3':
1167 log_info("-3 option given. Set frame to %s.\n", optarg);
1168 setFrameNumber(atoi(optarg));
1169 break;
1170
1171 case '4':
1172 log_info("-4 option given. Exit at frame %s.\n", optarg);
1173 exitAtFrameNumber = atoi(optarg);
1174 exitAtFrame = true;
1175 break;
1176
1177 case 'a':
1178 log_info("-a option given. Test mode for %s AI players.\n", optarg);
1179 testAI = atoi(optarg);
1180 break;
1181
1182 case 'c':
1183 setTeamMode(1);
1184 log_info("-c option given. Color team mode.\n");
1185 break;
1186
1187 case 's':
1188 setTeamMode(2);
1189 log_info("-s option given. Sex team mode.\n");
1190 break;
1191
1192 case 'k':
1193 setTeamMode(4);
1194 log_info("-k option given. Skynet team mode.\n");
1195 break;
1196
1197 case '2':
1198 log_info("-2 option given. Slow motion for AI debugging.\n");
1199 slowMode = true;
1200 break;
1201
1202 case 'z':
1203 music = false;
1204 break;
1205
1206 case 'x':
1207 log_info("-x xBRZ shader factor to %s.\n", optarg);
1208 xbrzFactor = atoi(optarg);
1209 if (xbrzFactor < 1)
1210 {
1211 xbrzFactor = 1;
1212 }
1213 if (xbrzFactor > 6)
1214 {
1215 xbrzFactor = 6;
1216 }
1217 break;
1218
1219 case 'd':
1220 joystickDeadZone = atoi(optarg);
1221 log_info("-d Joystick deadzone to %d.\n", joystickDeadZone);
1222 break;
1223 case 'e':
1224 log_info("-e Check Demo Mode.\n");
1225 checkDemoMode = true;
1226 // m.temps_avant_demo = 10;
1227 break;
1228
1229 default:
1230 exit(1);
1231 }
1232 }
1233 #if 0
1234 logDebug = fopen("/tmp/mrboom.log", "w");
1235 #endif
1236 /* Enable standard application logging */
1237 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
1238 SDL_EventState(SDL_JOYAXISMOTION, SDL_ENABLE);
1239 SDL_EventState(SDL_JOYBALLMOTION, SDL_ENABLE);
1240 SDL_EventState(SDL_JOYHATMOTION, SDL_ENABLE);
1241 SDL_EventState(SDL_JOYBUTTONDOWN, SDL_ENABLE);
1242 SDL_EventState(SDL_JOYBUTTONUP, SDL_ENABLE);
1243
1244 SDL_JoystickEventState(SDL_ENABLE);
1245
1246 if ((exitAtFrame) && (exitAtFrameNumber == -1))
1247 {
1248 log_info("No VGA\n");
1249 noVGA = SDL_TRUE;
1250 }
1251
1252 if ((noVGA == SDL_FALSE) && (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0))
1253 {
1254 log_error("Couldn't initialize SDL: %s\n", SDL_GetError());
1255 noVGA = SDL_TRUE;
1256 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1257 {
1258 log_error("Couldn't initialize SDL_INIT_JOYSTICK: %s\n", SDL_GetError());
1259 return(1);
1260 }
1261 }
1262
1263 if (!mrboom_init())
1264 {
1265 log_error("Error in init.\n");
1266 quit(1);
1267 }
1268 if (showVersion)
1269 {
1270 quit(0);
1271 }
1272 printKeys();
1273 #define RESIZABLE
1274 if (noVGA == SDL_FALSE)
1275 {
1276 /* Create the window and renderer */
1277 #ifndef FULLSCREEN
1278 #ifdef RESIZABLE
1279 window = SDL_CreateWindow(GAME_NAME,
1280 SDL_WINDOWPOS_UNDEFINED,
1281 SDL_WINDOWPOS_UNDEFINED,
1282 WIDTH * 3, HEIGHT * 3,
1283 SDL_WINDOW_RESIZABLE
1284 );
1285 windowID = SDL_GetWindowID(window);
1286 #else
1287 SDL_DisplayMode DM;
1288 SDL_GetCurrentDisplayMode(0, &DM);
1289 int displayWidth = DM.w;
1290 int displayHeight = DM.h;
1291
1292 float aspectRatio = (float)displayWidth / (float)displayHeight;
1293 float height;
1294 float width;
1295 if (aspectRatio < ASPECT_RATIO)
1296 {
1297 width = displayWidth;
1298 height = (1.f / ASPECT_RATIO) * displayWidth;
1299 }
1300 else
1301 {
1302 width = ASPECT_RATIO * displayHeight;
1303 height = displayHeight;
1304 }
1305
1306 window = SDL_CreateWindow(GAME_NAME,
1307 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
1308 width, height,
1309 SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
1310 );
1311 #endif
1312 #else
1313 // FULLSCREEN
1314 window = SDL_CreateWindow(GAME_NAME,
1315 SDL_WINDOWPOS_CENTERED,
1316 SDL_WINDOWPOS_CENTERED,
1317 WIDTH, HEIGHT,
1318 SDL_WINDOW_FULLSCREEN | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_GRABBED
1319 );
1320 #endif
1321
1322
1323 if (!window)
1324 {
1325 log_error("Couldn't set create window: %s\n", SDL_GetError());
1326 quit(3);
1327 }
1328 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
1329
1330 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
1331 if (!renderer)
1332 {
1333 log_error("Couldn't set create renderer: %s\n", SDL_GetError());
1334 quit(4);
1335 }
1336
1337 widthTexture = WIDTH * xbrzFactor;
1338 heightTexture = HEIGHT * xbrzFactor;
1339 texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, widthTexture, heightTexture);
1340 if (!texture)
1341 {
1342 log_error("Couldn't set create texture: %s\n", SDL_GetError());
1343 quit(5);
1344 }
1345 }
1346
1347 /* Loop, waiting for QUIT or the escape key */
1348
1349 #ifdef __EMSCRIPTEN__
1350 emscripten_set_main_loop(loop, 0, 1);
1351 #else
1352 begin = clock();
1353 while (!done)
1354 {
1355 if (resizeDone)
1356 {
1357 SDL_SetWindowSize(window, width, height);
1358 resizeDone = false;
1359 }
1360 loop();
1361 #ifdef DEBUG
1362 fps();
1363 if (testAI)
1364 {
1365 manageTestAI();
1366 }
1367 if (slowMode)
1368 {
1369 usleep(100000);
1370 }
1371 if ((exitAtFrame) && (frameNumber() == exitAtFrameNumber))
1372 {
1373 log_info("Exit at frame\n");
1374 exit(0);
1375 }
1376 if ((exitAtFrame) && (exitAtFrameNumber == -1))
1377 {
1378 static bool first = false;
1379 if (isGameActive() == true)
1380 {
1381 first = true;
1382 }
1383 else
1384 {
1385 if (first)
1386 {
1387 log_info("Exit at frame\n");
1388 for (int i = 0; i < nb_dyna; i++)
1389 {
1390 if (victories(i))
1391 {
1392 log_info("team %d won\n", teamOfPlayer(i));
1393 exit(i);
1394 }
1395 }
1396 log_info("draw game\n");
1397 exit(nb_dyna);
1398 }
1399 }
1400 }
1401 #endif
1402 }
1403 #endif
1404
1405 if (noVGA == SDL_FALSE)
1406 {
1407 SDL_DestroyRenderer(renderer);
1408 }
1409 fps();
1410 log_debug("quit(0)\n");
1411 quit(0);
1412 return 0;
1413 }
1414