2 // Thunder Graphic User Interface
5 // (C) 2004, 2014 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- -----------------------------------------------------------
11 // JLH 07/23/2009 Added changelog ;-)
19 #include "resource.h" // Thunder graphics & sounds
25 extern uint8_t my_scr[0x14000]; // Screen buffer...
26 extern uint8_t gram1[]; // Game RAM (do here??)
30 uint16_t text_life; // How long text is visible
31 bool show_text; // Whether or not to show text
32 uint16_t show_which_msg; // Which message to show
33 bool show_gui; // Whether or not to show GUI
34 uint16_t selection; // Which GUI item currently selected
35 uint16_t gui_debounce; // GUI key debounce value
36 uint16_t num_coins; // Number of coins dropped
37 uint16_t blink = 0; // Used to blink player 1 & 2 start buttons
38 uint16_t flash = 23; // Used to flash GUI lights
39 uint16_t iline = 0; // Used to roll line
40 uint16_t dcurcol = 179; // dipswitch cursor color
41 int dcurdir = 1; // Initially going up...
42 bool blink_on = false;
43 bool game_refresh; // Refresh rate user set
44 bool do_decrement; // Flag to handle decrement...
45 bool user_selected_something; // Flag for well, you know...
46 uint16_t dswitch; // Which dipswitch is selected...
51 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
52 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
53 0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
54 0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
55 0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
56 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
57 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
60 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
61 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
62 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
63 0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
64 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
65 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
66 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
69 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
70 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
71 0,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,
72 0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,
73 0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,0,
74 0,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,
75 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0
77 uint8_t boptions[] = { // 35x9
78 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
79 0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
80 0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
81 0,1,0,0,1,0,1,1,1,0,0,1,1,1,1,0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,0,1,1,0,0,
82 0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,
83 0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,0,
84 0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,
85 0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,
86 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
241 user_selected_something = false;
246 // Handle key debounce
248 void HandleGUIDebounce(void)
251 gui_debounce--; // Debounce GUI keys...
253 do_decrement = !do_decrement; // Called at 60Hz, so skip decrementing blink
258 blink--; // Handle blinking stuff (Should prb go in DrawGUI)
260 flash -= 2; // Handle flashing stuff (Should prb go in DrawGUI)
268 iline = 0; // 30 pixels high, going past by 1
282 // Set the refresh rate (30/60 Hz)
284 void SetRefreshRate(bool refresh)
286 game_refresh = refresh;
291 // Whether or not GUI is showing
302 void ActivateGUI(void)
311 void DeactivateGUI(void)
318 // Draw the small icons...
320 void DrawSmallIcons(uint16_t icon_not_to_draw)
324 uint8_t * sIcons[12] = { inoguis, icoinus, ipl1sts, ipl2sts, ii30hzs,
325 ii60hzs, idipsws, ichecks, ikeycns, isnapss, iresets, ibyebys };
326 uint8_t xlens[12] = { 31, 18, 32, 35, 37, 37, 29, 23, 28, 32, 19, 19 };
327 uint8_t ylens[12] = { 31, 18, 19, 19, 21, 21, 23, 20, 16, 17, 20, 23 };
328 uint8_t xpos[11] = { 33, 48, 63, 78, 104, 0, 184, 210, 225, 240, 255 };
329 uint8_t iconidx[11] = { 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 6 };
332 iconidx[9] = 5; // 60 Hz...
334 // Draw small icons 1 to 5 on left, then 11 to 7 on right.
336 for(int i=0; i<5; i++)
338 uint16_t idx = i + icon_not_to_draw; // Get correct start pos.
343 iconmem = sIcons[iconidx[idx]];
344 xl = xlens[iconidx[idx]];
345 yl = ylens[iconidx[idx]];
347 uint32_t scadr;// = hScrollOffset + voffsets[vScrollOffset];
348 scadr += 320 * ((224 - yl) / 2); // Center vertically
349 scadr += xpos[i] - (xl / 2); // Center around horiz. pos.
352 for(int yy=0; yy<yl; yy++)
354 for(int xx=0; xx<xl; xx++)
356 uint8_t b = iconmem[bmpptr++];
359 my_scr[scadr + xx + yy * 320] = b;
364 for(int i=10; i>5; i--)
366 uint16_t idx = i + icon_not_to_draw; // Get correct start pos.
371 iconmem = sIcons[iconidx[idx]];
372 xl = xlens[iconidx[idx]];
373 yl = ylens[iconidx[idx]];
375 uint32_t scadr;// = hScrollOffset + voffsets[vScrollOffset];
376 scadr += 320 * ((224 - yl) / 2); // Center vertically
377 scadr += xpos[i] - (xl / 2); // Center around horiz. pos.
380 for(int yy=0; yy<yl; yy++)
382 for(int xx=0; xx<xl; xx++)
384 uint8_t b = iconmem[bmpptr++];
387 my_scr[scadr + xx + yy * 320] = b;
395 // Draw the large (selected) icon
397 void DrawLargeIcon(uint16_t icon)
401 uint8_t * lIcons[11] = { inoguib, icoinub, ipl1stb, ipl2stb, ii30hzb,
402 ii60hzb, idipswb, ikeycnb, isnapsb, iresetb, ibyebyb };
403 uint8_t xlens[11] = { 44, 45, 50, 52, 59, 59, 42, 45, 48, 58, 42 };
404 uint8_t ylens[11] = { 44, 40, 33, 29, 52, 52, 34, 45, 37, 40, 50 };
406 uint8_t gsubs1[24] = { 21, 21, 20, 19, 168, 168, 31, 155, 68, 68, 67, 66,
407 36, 36, 35, 34, 188, 188, 183, 181, 81, 81, 85, 80 },
408 gsubs2[24] = { 20, 20, 19, 19, 31, 31, 155, 155, 67, 67, 66, 66,
409 35, 35, 34, 34, 183, 183, 181, 181, 85, 85, 80, 80 },
410 gsubs3[24] = { 35, 34, 188, 188, 183, 181, 81, 81, 85, 80, 21, 21,
411 20, 19, 168, 168, 31, 155, 68, 68, 67, 66, 36, 36 },
412 gsubs4[24] = { 34, 34, 183, 183, 181, 181, 85, 85, 80, 80, 20, 20,
413 19, 19, 31, 31, 155, 155, 67, 67, 66, 66, 35, 35 },
414 gsubs5[24] = { 20, 20, 183, 183, 31, 31, 85, 85, 67, 67, 20, 20,
415 35, 35, 31, 31, 183, 183, 67, 67, 85, 85, 35, 35 };
417 iconmem = lIcons[icon];
428 if ((icon == REFRESH) && game_refresh)
435 if (icon == DIPSWITCH)
442 uint32_t scadr;// = hScrollOffset + voffsets[vScrollOffset];
443 scadr += 320 * ((224 - yl) / 2); // Center vertically
444 scadr += (288 - xl) / 2; // Center horizontally
447 for(int yy=0; yy<yl; yy++)
449 for(int xx=0; xx<xl; xx++)
451 uint8_t b = iconmem[bmpptr++];
455 if ((icon == PL1START) && (b == 235) && (num_coins) && !blink_on)
456 b = 125; // Light ON color
457 /*noguib: 44x44 [Green (hi/lo): 36/235 Orange: 168/31 Neutral:12]
458 Rainbow (ROYGBP, hi/med/lo): 21,20,19; 168, 31,155; 68,67,66;
459 36,35,34; 188,183,181; 81,85,80 */
462 uint8_t fln = (23 - flash) + 1; // Want to go forward (maybe fix it?)
465 case 36: { b = gsubs1[fln]; break; }
466 case 235: { b = gsubs2[fln]; break; }
467 case 168: { b = gsubs3[fln]; break; }
468 case 31: { b = gsubs4[fln]; break; }
469 case 12: { b = gsubs5[fln]; break; }
473 if ((icon == REFRESH) && (iline == yy) && (b == 50))
476 my_scr[scadr+xx+yy*320] = b;
481 if (!blink) // Should go here???
483 blink_on = !blink_on; // Switch blink state
490 //if (flash == 1) flash = 23; // Reset flash value
495 // Draw the dipswitch portion of the GUI
497 void DrawDipswitch(void)
499 uint8_t dseloff[16] = { 0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 11, 12 };
500 uint8_t * dtxt[13] = { idstext1, idstext2, idstext3, idstext4, idstext5,
501 idstext2, idstext6, idstext7, idstext8, idstext9, idstext10, idstext11,
504 uint8_t dtx[13] = { 48, 80, 96, 82, 60, 80, 76, 57, 33, 50, 62, 65, 63 },
505 dty[13] = { 7, 9, 7, 9, 7, 9, 7, 7, 7, 9, 7, 9, 7 };
506 uint32_t dtxtoff[13] = { 4*320+24, 14*320-78, 25*320+24, 32*320-80,
507 39*320+24, 49*320-78, 4*320+24, 11*320-55, 18*320+24, 25*320-48,
508 32*320+24, 42*320-63, 53*320+24 };
509 uint32_t scadr, bmpptr;
512 uint32_t dbase;// = hScrollOffset + voffsets[vScrollOffset];
513 dbase += (288 - 26) / 2; // Center horizontally
514 dbase += 320 * ((224 - ((65 * 2) + 8)) / 2); // Center vertically
516 scadr = dbase; // Reset screen address
519 for(int yy=0; yy<65; yy++)
521 for(int xx=0; xx<26; xx++)
523 uint8_t b = idswitch[bmpptr++];
526 my_scr[scadr + xx + yy * 320] = b;
530 scadr = dbase + (320*73); // Reset screen address
533 for(int yy=0; yy<65; yy++)
535 for(int xx=0; xx<26; xx++)
537 uint8_t b = idswitch[bmpptr++];
540 my_scr[scadr + xx + yy * 320] = b;
544 for(int i=0; i<16; i++)
546 scadr = dbase + (5 * 320 + 5) + i * 7 * 320;
549 scadr += 17*320; // Adjust for DSW #2
553 if (gram1[0x423D + (i << 1)])
554 scadr += 12; // Adjust position if ON
556 for(int yy=0; yy<5; yy++)
558 for(int xx=0; xx<5; xx++)
560 my_scr[scadr++] = idsbutton[bmpptr++];
563 scadr += 315; // Adjust position...
567 uint8_t dselected_text = dseloff[dswitch];
569 for(int i=0; i<13; i++)
571 if (dselected_text != i)
573 scadr = dbase + dtxtoff[i];
580 for(int yy=0; yy<dty[i]; yy++)
582 for(int xx=0; xx<dtx[i]; xx++)
584 uint8_t b = dtxt[i][bmpptr++];
592 scadr += (320 - dtx[i]); // Adjust position...
597 scadr = dbase + dtxtoff[dselected_text];
599 if (dselected_text>5)
604 for(int yy=0; yy<dty[dselected_text]; yy++)
606 for(int xx=0; xx<dtx[dselected_text]; xx++)
608 uint8_t b = dtxt[dselected_text][bmpptr++];
616 scadr += (320 - dtx[dselected_text]); // Adjust position...
619 if (dswitch != 16) // Draw cursor
621 scadr = dbase + (4 * 320 + 4) + dswitch * 7 * 320;
624 scadr += 17 * 320; // Adjust for DSW #2
626 for(int xx=0; xx<19; xx++)
627 my_scr[scadr++] = dcurcol;
631 for(int xx=0; xx<5; xx++)
633 my_scr[scadr] = dcurcol;
635 my_scr[scadr] = dcurcol;
639 for(int xx=0; xx<19; xx++)
640 my_scr[scadr++] = dcurcol;
646 // The actual GUI display routine
650 if (!user_selected_something) // i.e. we're not inside a selection...
652 DrawSmallIcons(selection); // 'selection' is icon *not* to draw
653 DrawLargeIcon(selection);
657 if (selection == DIPSWITCH)
664 // User pressed left arrow handler
666 void SelectLeft(void)
672 if (!user_selected_something)
681 if (gram1[0x423D + (dswitch << 1)]) // It's switchable...
682 {} //SpawnSound(USERSOUND, SCLICK);
684 {} //SpawnSound(USERSOUND, SUNGH);
686 gram1[0x423D + (dswitch << 1)] = 0; // & turn it off
693 // User pressed right arrow handler
695 void SelectRight(void)
701 if (!user_selected_something)
706 selection = 10; // Unsigned compare
710 if (!gram1[0x423D + (dswitch << 1)]) // It's switchable...
711 {} //SpawnSound(USERSOUND, SCLICK);
713 {} //SpawnSound(USERSOUND, SUNGH);
715 gram1[0x423D+(dswitch<<1)] = 1; // & turn it on
722 // User pressed Up arrow handler
730 if (user_selected_something)
732 if (selection == DIPSWITCH)
737 dswitch = 16; // Wrap non-int
738 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
746 // User pressed down arrow handler
748 void SelectDown(void)
754 if (user_selected_something)
756 if (selection == DIPSWITCH)
762 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
770 // User selected something! Handle it!
772 uint8_t UserSelectedSomething(void)
774 //extern uint8_t * gram1;
780 if (!user_selected_something) // Inside a selection? no...
783 if (selection == NOGUI) // Turn off GUI
788 if (selection == COINUP) // Coin up machine
790 gram1[0x41A5]++; // Add one coin... (prob. need sep. counter)
792 gram1[0x4189] = num_coins / 10; // Should be in THUNDER.CPP?
793 gram1[0x418A] = num_coins - (gram1[0x4189] * 10);
796 if (selection == PL1START) // 1 Player start
801 show_gui = false; // Shut off GUI only if coined up
804 gram1[0x418C] = 1; // Strobe start location
807 if (selection == PL2START) // 2 Player start
816 if (selection == REFRESH) // Toggle refresh rate
818 //SpawnSound(USERSOUND, SCLICK);
821 if (selection == DIPSWITCH) // Edit game settings
823 //SpawnSound(USERSOUND, SBLAH);
824 user_selected_something = true;
825 dswitch = 0; // Set at first dipswitch
828 if (selection == OPTIONS) // Edit emulator settings
832 if (selection == KEYCONFIG) // Edit game keys
836 if (selection == SNAPSHOT) // Snapshot
838 SpawnSound(USERSOUND, SCAMERA);
842 if (selection == RESET) // Reset machine
844 //SpawnSound(USERSOUND, SRESET);
847 if (selection == EXIT)
849 SpawnSound(USERSOUND, SCYA);
854 else // Selected something inside selection...
856 if (selection == DIPSWITCH)
858 if (dswitch == 16) // Selected 'back to GUI'
860 //SpawnSound(USERSOUND, SBLAH2);
861 user_selected_something = false;
865 //SpawnSound(USERSOUND, SCLICK);
866 gram1[0x423D + (dswitch << 1)] = !gram1[0x423D + (dswitch << 1)];
870 return 0xFF; // Nothing for main to do...
874 return 0xFF; // Wasn't debounced, so return invalid
879 // Show byte passed to it
881 void ShowNumbers(int number)
883 uint8_t * bnarray[16] = { bn0, bn1, bn2, bn3, bn4, bn5, bn6, bn7, bn8, bn9,
884 bnA, bnB, bnC, bnD, bnE, bnF };
885 // uint32_t scadr = hScrollOffset + voffsets[vScrollOffset] + 642 + 2560;
886 uint32_t scadr = ((2 * 288) + 2) + (8 * 288);
889 uint8_t first_dig = number >> 4, second_dig = number & 0x0F;
891 for(int y=0; y<7; y++)
893 for(int x=0; x<6; x++)
895 if (bnarray[first_dig][bmpptr++] == 1)
896 // my_scr[scadr + x + y * 320] = 7;
897 my_scr[scadr + x + y * 288] = 7;
899 // my_scr[scadr + x + y * 320] = 0;
900 my_scr[scadr + x + y * 288] = 0;
907 for(int y=0; y<7; y++)
909 for(int x=0; x<6; x++)
911 if (bnarray[second_dig][bmpptr++] == 1)
912 // my_scr[scadr + x + y * 320] = 7;
913 my_scr[scadr + x + y * 288] = 7;
915 // my_scr[scadr + x + y * 320] = 0;
916 my_scr[scadr + x + y * 288] = 0;
925 void SpawnMsg(uint8_t msg)
927 text_life = 60; // 1 second...
928 show_text = true; // Show the damn thing...
929 show_which_msg = msg; // And tell it which message to show...
938 // Kill text if it's time
945 // Your life force is running out...
948 // Draw the message here...
949 // uint32_t scadr = hScrollOffset + voffsets[vScrollOffset] + 642;
950 uint32_t scadr = (288 * 2) + 2;
953 for(int y=0; y<7; y++)
955 for(int x=0; x<21; x++)
957 if (show_which_msg == M60FPS)
959 if (bmp1[bmpptr++] == 1)
960 // my_scr[scadr + x + y * 320] = 7;
961 my_scr[scadr + x + y * 288] = 7;
963 // my_scr[scadr + x + y * 320] = 0;
964 my_scr[scadr + x + y * 288] = 0;
966 else if (show_which_msg == M30FPS)
968 if (bmp2[bmpptr++] == 1)
969 // my_scr[scadr + x + y * 320] = 7;
970 my_scr[scadr + x + y * 288] = 7;
972 // my_scr[scadr + x + y * 320] = 0;
973 my_scr[scadr + x + y * 288] = 0;
975 else if (show_which_msg == MSNAPSHOT)
977 if (bmp3[bmpptr++] == 1)
978 // my_scr[scadr + x + y * 320] = 7;
979 my_scr[scadr + x + y * 288] = 7;
981 // my_scr[scadr + x + y * 320] = 0;
982 my_scr[scadr + x + y * 288] = 0;
987 if (show_which_msg == MSHOWNUMS)
988 ShowNumbers(snd_num);