]> Shamusworld >> Repos - thunder/blob - src/gui.cpp
640b70fcf213f2572d1f16ead9939acfc65659be
[thunder] / src / gui.cpp
1 //
2 // Thunder Graphic User Interface
3 // v1.0 (Last build: 8/1/1998)
4 //
5 // by Jimmy Hamm
6 // (C) 1998 Underground Software
7 //
8
9 #include <string>
10 #include <fstream>       // Needed for tracelog
11 #include "SDL.h"         // Needed for screen.h
12 #include "screen.h"
13 #include "gui.h"
14 #include "resource.h"    // Thunder graphics & sounds
15
16 using namespace std;                                    // Yes!
17
18 // External shit
19
20 extern SDL_Surface * screen;
21
22 extern BYTE my_scr[0x14000];                                                    // Screen buffer...
23 extern BYTE * gram1;                                                                    // Game RAM (do here??)
24 extern BYTE hScrollOffset;                                                              // Horizontal scroll offset
25 extern BYTE vScrollOffset;                                                              // Vertical scroll offset
26 extern DWORD voffsets[8];
27 extern BYTE * voice_rom;                                                                // PCM data pointer
28 extern fstream tr;                                                                              // Tracelog
29
30 // Global shit
31
32 WORD text_life;          // How long text is visible
33 bool show_text;          // Whether or not to show text
34 WORD show_which_msg;     // Which message to show
35 bool show_gui;           // Whether or not to show GUI
36 WORD selection;          // Which GUI item currently selected
37 WORD snd_num;
38 WORD gui_debounce;       // GUI key debounce value
39 WORD num_coins;          // Number of coins dropped
40 WORD blink = 0;          // Used to blink player 1 & 2 start buttons
41 WORD flash = 23;         // Used to flash GUI lights
42 WORD iline = 0;          // Used to roll line
43 WORD dcurcol = 179;      // dipswitch cursor color
44 int  dcurdir = 1;        // Initially going up...
45 bool blink_on = false;
46 bool game_refresh;       // Refresh rate user set
47 bool do_decrement;       // Flag to handle decrement...
48 bool user_selected_something;  // Flag for well, you know...
49 WORD dswitch;            // Which dipswitch is selected...
50
51 // The following are global for the sound routines...
52
53 const float sampleBase = 22050.0/6000.0;  // Btwn 5512.5 and 6000
54 bool snd_go = false;
55 bool chan1_go = false, chan2_go = false, chan3_go = false;
56 bool chan4_go = false, chan5_go = false, chan6_go = false;
57 BYTE * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6;
58 uint32 rom_pos, end_pos;
59 uint32 spos1, end_pos1;
60 uint32 spos2, end_pos2;
61 uint32 spos3, end_pos3;
62 uint32 spos4, end_pos4;
63 uint32 spos5, end_pos5;
64 uint32 spos6, end_pos6;
65 float sample1;
66 uint8 prevSamp1;
67 int8 delta_x1;
68 float sample2;
69 uint8 prevSamp2;
70 int8 delta_x2;
71
72 BYTE * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
73 DWORD snd_lens[3]   = { sunknownlen, scyalen, scameralen };
74
75 // Bitmaps
76
77 BYTE bmp1[] = {
78   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,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
80   0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
81   0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
82   0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
83   0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
84   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
85   };
86 BYTE bmp2[] = {
87   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
88   0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
89   0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
90   0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
91   0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
92   0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
93   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
94   };
95 BYTE bmp3[] = {
96   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
97   0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98   0,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,
99   0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,
100   0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,0,
101   0,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,
102   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0
103   };
104 BYTE boptions[] = { // 35x9
105   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,
106   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,
107   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,
108   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,
109   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,
110   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,
111   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,
112   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,
113   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
114   };
115 BYTE bn0[] = {
116   0,0,0,0,0,0,
117   0,0,1,1,0,0,
118   0,1,0,0,1,0,
119   0,1,0,0,1,0,
120   0,1,0,0,1,0,
121   0,0,1,1,0,0,
122   0,0,0,0,0,0 
123   };
124 BYTE bn1[] = {
125   0,0,0,0,0,0,
126   0,0,1,0,0,0,
127   0,1,1,0,0,0,
128   0,0,1,0,0,0,
129   0,0,1,0,0,0,
130   0,1,1,1,0,0,
131   0,0,0,0,0,0 
132   };
133 BYTE bn2[] = {
134   0,0,0,0,0,0,
135   0,1,1,1,0,0,
136   0,0,0,0,1,0,
137   0,0,1,1,0,0,
138   0,1,0,0,0,0,
139   0,1,1,1,1,0,
140   0,0,0,0,0,0 
141   };
142 BYTE bn3[] = {
143   0,0,0,0,0,0,
144   0,1,1,1,0,0,
145   0,0,0,0,1,0,
146   0,1,1,1,0,0,
147   0,0,0,0,1,0,
148   0,1,1,1,0,0,
149   0,0,0,0,0,0 
150   };
151 BYTE bn4[] = {
152   0,0,0,0,0,0,
153   0,0,0,1,0,0,
154   0,1,0,1,0,0,
155   0,1,0,1,0,0,
156   0,1,1,1,1,0,
157   0,0,0,1,0,0,
158   0,0,0,0,0,0 
159   };
160 BYTE bn5[] = {
161   0,0,0,0,0,0,
162   0,1,1,1,1,0,
163   0,1,0,0,0,0,
164   0,1,1,1,0,0,
165   0,0,0,0,1,0,
166   0,1,1,1,0,0,
167   0,0,0,0,0,0 
168   };
169 BYTE bn6[] = {
170   0,0,0,0,0,0,
171   0,0,1,1,0,0,
172   0,1,0,0,0,0,
173   0,1,1,1,0,0,
174   0,1,0,0,1,0,
175   0,0,1,1,0,0,
176   0,0,0,0,0,0 
177   };
178 BYTE bn7[] = {
179   0,0,0,0,0,0,
180   0,1,1,1,1,0,
181   0,0,0,0,1,0,
182   0,0,0,1,0,0,
183   0,0,1,0,0,0,
184   0,0,1,0,0,0,
185   0,0,0,0,0,0 
186   };
187 BYTE bn8[] = {
188   0,0,0,0,0,0,
189   0,0,1,1,0,0,
190   0,1,0,0,1,0,
191   0,0,1,1,0,0,
192   0,1,0,0,1,0,
193   0,0,1,1,0,0,
194   0,0,0,0,0,0 
195   };
196 BYTE bn9[] = {
197   0,0,0,0,0,0,
198   0,0,1,1,0,0,
199   0,1,0,0,1,0,
200   0,0,1,1,1,0,
201   0,0,0,0,1,0,
202   0,0,1,1,0,0,
203   0,0,0,0,0,0 
204   };
205 BYTE bnA[] = {
206   0,0,0,0,0,0,
207   0,0,1,1,0,0,
208   0,1,0,0,1,0,
209   0,1,1,1,1,0,
210   0,1,0,0,1,0,
211   0,1,0,0,1,0,
212   0,0,0,0,0,0 
213   };
214 BYTE bnB[] = {
215   0,0,0,0,0,0,
216   0,1,1,1,0,0,
217   0,1,0,0,1,0,
218   0,1,1,1,0,0,
219   0,1,0,0,1,0,
220   0,1,1,1,0,0,
221   0,0,0,0,0,0 
222   };
223 BYTE bnC[] = {
224   0,0,0,0,0,0,
225   0,0,1,1,0,0,
226   0,1,0,0,1,0,
227   0,1,0,0,0,0,
228   0,1,0,0,1,0,
229   0,0,1,1,0,0,
230   0,0,0,0,0,0 
231   };
232 BYTE bnD[] = {
233   0,0,0,0,0,0,
234   0,1,1,1,0,0,
235   0,1,0,0,1,0,
236   0,1,0,0,1,0,
237   0,1,0,0,1,0,
238   0,1,1,1,0,0,
239   0,0,0,0,0,0 
240   };
241 BYTE bnE[] = {
242   0,0,0,0,0,0,
243   0,1,1,1,1,0,
244   0,1,0,0,0,0,
245   0,1,1,1,1,0,
246   0,1,0,0,0,0,
247   0,1,1,1,1,0,
248   0,0,0,0,0,0 
249   };
250 BYTE bnF[] = {
251   0,0,0,0,0,0,
252   0,1,1,1,1,0,
253   0,1,0,0,0,0,
254   0,1,1,1,0,0,
255   0,1,0,0,0,0,
256   0,1,0,0,0,0,
257   0,0,0,0,0,0 
258   };
259
260 //
261 // Initialize GUI
262 //
263 void InitGUI(void)
264 {
265         num_coins = 0;
266         gui_debounce = 0;
267         user_selected_something = false;
268 }
269
270 //
271 // Handle key debounce
272 //
273 void HandleGUIDebounce(void)
274 {
275   if (gui_debounce)  gui_debounce--;   // Debounce GUI keys...
276   do_decrement = !do_decrement;        // Called at 60Hz, so skip decrementing blink
277   if (do_decrement)
278   {
279     if (blink)  blink--;  // Handle blinking stuff (Should prb go in DrawGUI)
280
281     flash-=2;  // Handle flashing stuff (Should prb go in DrawGUI)
282     if (flash == 0xFFFF)  flash = 23;
283
284     iline++;
285     if (iline > 30)  iline = 0;  // 30 pixels high, going past by 1
286
287     dcurcol += dcurdir;
288     if (dcurcol == 186)  dcurdir = -1;
289     if (dcurcol == 179)  dcurdir = 1;
290   }
291 }
292
293 //
294 // Set the refresh rate (30/60 Hz)
295 //
296 void SetRefreshRate(bool refresh)
297 {
298   game_refresh = refresh;
299 }
300
301 //
302 // Whether or not GUI is showing
303 //
304 bool ShowGUI(void)  { return show_gui; }
305
306 //
307 // Turn the GUI on
308 //
309 void ActivateGUI(void)  { show_gui = true; }
310
311 //
312 // Turn the GUI off
313 //
314 void DeactivateGUI(void)  { show_gui = false; }
315
316 //
317 // Draw the small icons...
318 //
319 void DrawSmallIcons(WORD icon_not_to_draw)
320 {
321   BYTE * iconmem;
322   BYTE xl, yl;
323   BYTE * sIcons[12] = { inoguis, icoinus, ipl1sts, ipl2sts, ii30hzs, ii60hzs,
324                         idipsws, ichecks, ikeycns, isnapss, iresets, ibyebys };
325   BYTE xlens[12] = { 31, 18, 32, 35, 37, 37, 29, 23, 28, 32, 19, 19 };
326   BYTE ylens[12] = { 31, 18, 19, 19, 21, 21, 23, 20, 16, 17, 20, 23 };
327   BYTE xpos[11] = { 33, 48, 63, 78, 104, 0, 184, 210, 225, 240, 255 };
328   BYTE iconidx[11] = { 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 6 };
329
330   if (game_refresh)  iconidx[9] = 5;       // 60 Hz...
331
332   // Draw small icons 1 to 5 on left, then 11 to 7 on right.
333
334   for(int i=0; i<5; i++)
335   {
336     WORD idx = i + icon_not_to_draw;          // Get correct start pos.
337     if (idx > 10)  idx -= 11;
338
339     iconmem = sIcons[iconidx[idx]];
340     xl = xlens[iconidx[idx]];  yl = ylens[iconidx[idx]];
341
342     DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
343     scadr += 320*((224-yl)/2);                // Center vertically
344     scadr += xpos[i] - (xl/2);                // Center around horiz. pos.
345     WORD bmpptr = 0;
346
347     for(int yy=0; yy<yl; yy++)
348     {
349       for(int xx=0; xx<xl; xx++)
350       {
351         BYTE b = iconmem[bmpptr++];
352         if (b)  my_scr[scadr+xx+yy*320] = b;
353       }
354     }
355   }
356   for(int i=10; i>5; i--)
357   {
358     WORD idx = i + icon_not_to_draw;          // Get correct start pos.
359     if (idx > 10)  idx -= 11;
360
361     iconmem = sIcons[iconidx[idx]];
362     xl = xlens[iconidx[idx]];  yl = ylens[iconidx[idx]];
363
364     DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
365     scadr += 320*((224-yl)/2);                // Center vertically
366     scadr += xpos[i] - (xl/2);     // Center around horiz. pos.
367     WORD bmpptr = 0;
368
369     for(int yy=0; yy<yl; yy++)
370     {
371       for(int xx=0; xx<xl; xx++)
372       {
373         BYTE b = iconmem[bmpptr++];
374         if (b)  my_scr[scadr+xx+yy*320] = b;
375       }
376     }
377   }
378 }
379
380 //
381 // Draw the large (selected) icon
382 //
383 void DrawLargeIcon(WORD icon)
384 {
385   BYTE * iconmem;
386   BYTE xl, yl;
387   BYTE * lIcons[11] = { inoguib, icoinub, ipl1stb, ipl2stb, ii30hzb, ii60hzb,
388                         idipswb, ikeycnb, isnapsb, iresetb, ibyebyb };
389   BYTE xlens[11] = { 44, 45, 50, 52, 59, 59, 42, 45, 48, 58, 42 };
390   BYTE ylens[11] = { 44, 40, 33, 29, 52, 52, 34, 45, 37, 40, 50 };
391
392   BYTE gsubs1[24] = { 21, 21, 20, 19, 168, 168, 31, 155, 68, 68, 67, 66,
393                       36, 36, 35, 34, 188, 188, 183, 181, 81, 81, 85, 80 },
394        gsubs2[24] = { 20, 20, 19, 19, 31,  31,  155, 155, 67, 67, 66, 66,
395                       35, 35, 34, 34, 183, 183, 181, 181, 85, 85, 80, 80 },
396        gsubs3[24] = { 35, 34, 188, 188, 183, 181, 81, 81, 85, 80, 21, 21,
397                       20, 19, 168, 168, 31, 155, 68, 68, 67, 66, 36, 36 },
398        gsubs4[24] = { 34, 34, 183, 183, 181, 181, 85, 85, 80, 80, 20, 20,
399                       19, 19, 31,  31,  155, 155, 67, 67, 66, 66, 35, 35 },
400        gsubs5[24] = { 20, 20, 183, 183, 31, 31, 85, 85, 67, 67, 20, 20,
401                       35, 35, 31, 31, 183, 183, 67, 67, 85, 85, 35, 35 };
402
403   iconmem = lIcons[icon];
404   xl = xlens[icon];  yl = ylens[icon];
405   if (icon == OPTIONS)
406   {
407     iconmem = boptions;
408     xl = 35;  yl = 9;
409   }
410   if ((icon == REFRESH) && game_refresh)
411   {
412     iconmem = lIcons[5];
413     xl = xlens[5];  yl = ylens[5];
414   }
415   if (icon == DIPSWITCH)
416   {
417     iconmem = lIcons[6];
418     xl = xlens[6];  yl = ylens[6];
419   }
420
421   DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
422   scadr += 320*((224-yl)/2);                // Center vertically
423   scadr += (288-xl)/2;                      // Center horizontally
424   WORD bmpptr = 0;
425
426   for(int yy=0; yy<yl; yy++)
427   {
428     for(int xx=0; xx<xl; xx++)
429     {
430       BYTE b = iconmem[bmpptr++];
431       if (b)
432       {
433         if ((icon == PL1START) && (b == 235) && (num_coins) && !blink_on)
434           b = 125;                        // Light ON color
435 /*noguib: 44x44 [Green (hi/lo): 36/235 Orange: 168/31 Neutral:12]
436    Rainbow (ROYGBP, hi/med/lo): 21,20,19; 168, 31,155; 68,67,66;
437                                 36,35,34; 188,183,181; 81,85,80 */
438         if (icon == NOGUI)
439         {
440           BYTE fln = (23 - flash) + 1; // Want to go forward (maybe fix it?)
441           switch (b)
442           {
443             case 36:   { b = gsubs1[fln];  break; }
444             case 235:  { b = gsubs2[fln];  break; }
445             case 168:  { b = gsubs3[fln];  break; }
446             case 31:   { b = gsubs4[fln];  break; }
447             case 12:   { b = gsubs5[fln];  break; }
448           }
449         }
450         if ((icon == REFRESH) && (iline == yy) && (b == 50))  b = 188;
451         my_scr[scadr+xx+yy*320] = b;
452       }
453     }
454   }
455   if (!blink)    // Should go here???
456   {
457     blink_on = !blink_on;        // Switch blink state
458     if (blink_on)  blink = 12;
459     else           blink = 6;
460   }
461   //if (flash == 1)  flash = 23;       // Reset flash value
462 }
463
464 //
465 // Draw the dipswitch portion of the GUI
466 //
467 void DrawDipswitch(void)
468 {
469   BYTE dseloff[16] = { 0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 11, 12 };
470   BYTE * dtxt[13] = { idstext1, idstext2, idstext3, idstext4, idstext5,
471                       idstext2, idstext6, idstext7, idstext8, idstext9,
472                       idstext10, idstext11, idstext12 };
473
474   BYTE dtx[13] = { 48, 80, 96, 82, 60, 80, 76, 57, 33, 50, 62, 65, 63 },
475        dty[13] = { 7, 9, 7, 9, 7, 9, 7, 7, 7, 9, 7, 9, 7 };
476   DWORD dtxtoff[13] = { 4*320+24, 14*320-78, 25*320+24, 32*320-80,
477                         39*320+24, 49*320-78,
478                         4*320+24, 11*320-55, 18*320+24, 25*320-48,
479                         32*320+24, 42*320-63, 53*320+24 };
480   DWORD scadr, bmpptr;
481   //dsx = //26x65
482
483   DWORD dbase = hScrollOffset + voffsets[vScrollOffset];
484   dbase += (288-26)/2;                 // Center horizontally
485   dbase += 320*((224-((65*2)+8))/2);   // Center vertically
486
487   scadr = dbase;   // Reset screen address
488   bmpptr = 0;
489   for(int yy=0; yy<65; yy++)
490   {
491     for(int xx=0; xx<26; xx++)
492     {
493       BYTE b = idswitch[bmpptr++];
494       if (b)  my_scr[scadr+xx+yy*320] = b;
495     }
496   }
497   scadr = dbase + (320*73);   // Reset screen address
498   bmpptr = 0;
499   for(int yy=0; yy<65; yy++)
500   {
501     for(int xx=0; xx<26; xx++)
502     {
503       BYTE b = idswitch[bmpptr++];
504       if (b)  my_scr[scadr+xx+yy*320] = b;
505     }
506   }
507   for(int i=0; i<16; i++)                 
508   {
509     scadr = dbase + (5*320+5) + i*7*320;
510     if (i>7)  scadr += 17*320;   // Adjust for DSW #2
511     bmpptr = 0;
512     if (gram1[0x423D+(i<<1)])  scadr += 12; // Adjust position if ON
513     for(int yy=0; yy<5; yy++)
514     {
515       for(int xx=0; xx<5; xx++)
516       {
517         my_scr[scadr++] = idsbutton[bmpptr++]; 
518       }
519       scadr += 315; // Adjust position...
520     }
521   }
522   BYTE dselected_text = dseloff[dswitch];
523   for(int i=0; i<13; i++)
524   {
525     if (dselected_text != i)
526     {
527       scadr = dbase + dtxtoff[i];
528       if (i>5)  scadr += (73*320);
529       bmpptr = 0;
530       for(int yy=0; yy<dty[i]; yy++)
531       {
532         for(int xx=0; xx<dtx[i]; xx++)
533         {
534           BYTE b = dtxt[i][bmpptr++];
535           if (b)  my_scr[scadr] = b;
536           scadr++;
537         }
538         scadr += (320-dtx[i]); // Adjust position...
539       }
540     }
541   }
542   scadr = dbase + dtxtoff[dselected_text];
543   if (dselected_text>5)  scadr += (73*320);
544   bmpptr = 0;
545   for(int yy=0; yy<dty[dselected_text]; yy++)
546   {
547     for(int xx=0; xx<dtx[dselected_text]; xx++)
548     {
549       BYTE b = dtxt[dselected_text][bmpptr++];
550       if (b)  my_scr[scadr] = 125;
551       scadr++;
552     }
553     scadr += (320-dtx[dselected_text]); // Adjust position...
554   }
555   if (dswitch != 16)                   // Draw cursor
556   {
557     scadr = dbase + (4*320+4) + dswitch*7*320;
558     if (dswitch>7)  scadr += 17*320;   // Adjust for DSW #2
559     for(int xx=0; xx<19; xx++)  my_scr[scadr++] = dcurcol;
560     scadr += 301;
561     for(int xx=0; xx<5; xx++)
562     {
563       my_scr[scadr] = dcurcol;  scadr += 18;
564       my_scr[scadr] = dcurcol;  scadr += 302;
565     }
566     for(int xx=0; xx<19; xx++)  my_scr[scadr++] = dcurcol;
567   }
568 }
569
570 //
571 // The actual GUI display routine
572 //
573 void DrawGUI(void)
574 {
575   if (!user_selected_something)  // i.e. we're not inside a selection...
576   {
577     DrawSmallIcons(selection);  // 'selection' is icon *not* to draw
578     DrawLargeIcon(selection); 
579   }
580   else
581   {
582     if (selection == DIPSWITCH)  DrawDipswitch();
583   }
584 }
585
586 //
587 // User pressed left arrow handler
588 //
589 void SelectLeft(void)
590 {
591   if (!gui_debounce)
592   {
593     gui_debounce = 6;
594     if (!user_selected_something)
595     {
596       selection++;
597       if (selection > 10)  selection = 0;
598     }
599     else
600     {
601       if (gram1[0x423D+(dswitch<<1)])       // It's switchable...
602       {}  //SpawnSound(USERSOUND, SCLICK);
603       else
604       {}  //SpawnSound(USERSOUND, SUNGH);
605       gram1[0x423D+(dswitch<<1)] = 0;       // & turn it off
606     }
607   }
608 }
609
610 //
611 // User pressed right arrow handler
612 //
613 void SelectRight(void)
614 {
615   if (!gui_debounce)
616   {
617     gui_debounce = 6;
618     if (!user_selected_something)
619     {
620       selection--;
621       if (selection > 10)  selection = 10;  // Unsigned compare
622     }
623     else
624     {
625       if (!gram1[0x423D+(dswitch<<1)])       // It's switchable...
626       {}  //SpawnSound(USERSOUND, SCLICK);
627       else
628       {}  //SpawnSound(USERSOUND, SUNGH);
629       gram1[0x423D+(dswitch<<1)] = 1;       // & turn it on
630     }
631   }
632 }
633
634 //
635 // User pressed Up arrow handler
636 //
637 void SelectUp(void)
638 {
639   if (!gui_debounce)
640   {
641     gui_debounce = 6;
642     if (user_selected_something)
643     {
644       if (selection == DIPSWITCH)
645       {
646         dswitch--;
647         if (dswitch > 16)  dswitch = 16;  // Wrap non-int
648         //snd_num = dswitch;  SpawnMsg(MSHOWNUMS); // Temp...
649       }
650     }
651   }
652 }
653
654 //
655 // User pressed down arrow handler
656 //
657 void SelectDown(void)
658 {
659   if (!gui_debounce)
660   {
661     gui_debounce = 6;
662     if (user_selected_something)
663     {
664       if (selection == DIPSWITCH)
665       {
666         dswitch++;
667         if (dswitch > 16)  dswitch = 0;
668         //snd_num = dswitch;  SpawnMsg(MSHOWNUMS); // Temp...
669       }
670     }
671   }
672 }
673
674 //
675 // User selected something! Handle it!
676 //
677 BYTE UserSelectedSomething(void)
678 {
679   //extern BYTE * gram1;
680
681   if (!gui_debounce)
682   {
683     gui_debounce = 6;
684     if (!user_selected_something)  // Inside a selection? no...
685     {
686       if (selection == NOGUI)     // Turn off GUI
687       {
688         show_gui = false;
689       }
690       if (selection == COINUP)    // Coin up machine
691       {
692         gram1[0x41A5]++;          // Add one coin... (prob. need sep. counter)
693         num_coins++;
694         gram1[0x4189] = num_coins/10; // Should be in THUNDER.CPP?
695         gram1[0x418A] = num_coins - (gram1[0x4189]*10);
696       }
697       if (selection == PL1START)  // 1 Player start
698       {
699         if (num_coins)
700         {
701           num_coins--;
702           show_gui = false;       // Shut off GUI only if coined up
703         }
704         gram1[0x418C] = 1;        // Strobe start location
705       }
706       if (selection == PL2START)  // 2 Player start
707       {
708         if (num_coins > 1)
709         {
710           num_coins -= 2;
711           show_gui = false;
712         }
713       }
714       if (selection == REFRESH)   // Toggle refresh rate
715       {
716         //SpawnSound(USERSOUND, SCLICK);
717       }
718       if (selection == DIPSWITCH) // Edit game settings
719       {
720         //SpawnSound(USERSOUND, SBLAH);
721         user_selected_something = true;
722         dswitch = 0;              // Set at first dipswitch
723       } 
724       if (selection == OPTIONS)   // Edit emulator settings
725       {
726       }
727       if (selection == KEYCONFIG) // Edit game keys
728       {
729       }
730       if (selection == SNAPSHOT)  // Snapshot
731       {
732         SpawnSound(USERSOUND, SCAMERA);     
733         SnapPCX(screen);
734       }
735       if (selection == RESET)     // Reset machine
736       {
737         //SpawnSound(USERSOUND, SRESET);
738       }
739       if (selection == EXIT)
740       {
741         SpawnSound(USERSOUND, SCYA);
742       }
743       return selection;
744     }
745     else           // Selected something inside selection...
746     {
747       if (selection == DIPSWITCH)
748       {
749         if (dswitch == 16)  // Selected 'back to GUI'
750         {
751           //SpawnSound(USERSOUND, SBLAH2);
752           user_selected_something = false;
753         }
754         else
755         {
756           //SpawnSound(USERSOUND, SCLICK);
757           gram1[0x423D + (dswitch<<1)] = !gram1[0x423D + (dswitch<<1)];
758         }
759       }
760       return 0xFF;  // Nothing for main to do...
761     }
762   }
763   else  return 0xFF;  // Wasn't debounced, so return invalid
764 }
765
766 //
767 // Show byte passed to it
768 //
769 void ShowNumbers(int number)
770 {
771   BYTE * bnarray[16] = { bn0, bn1, bn2, bn3, bn4, bn5, bn6, bn7, bn8, bn9,
772     bnA, bnB, bnC, bnD, bnE, bnF };
773   DWORD scadr = hScrollOffset + voffsets[vScrollOffset] + 642 + 2560;
774   WORD bmpptr = 0;
775
776   BYTE first_dig = number>>4, second_dig = number&0x0F;
777   for(int y=0; y<7; y++)
778   {
779     for(int x=0; x<6; x++)
780     {
781       if (bnarray[first_dig][bmpptr++] == 1)  my_scr[scadr+x+y*320] = 7;
782       else                                    my_scr[scadr+x+y*320] = 0;
783     }
784   }
785   bmpptr = 0;  scadr += 6;
786   for(int y=0; y<7; y++)
787   {
788     for(int x=0; x<6; x++)
789     {
790       if (bnarray[second_dig][bmpptr++] == 1)  my_scr[scadr+x+y*320] = 7;
791       else                                     my_scr[scadr+x+y*320] = 0;
792     }
793   }
794 }
795
796 //
797 // Spawn a message
798 //
799 void SpawnMsg(BYTE msg)
800 {
801         text_life = 60;                                                                         // 1 second...
802         show_text = true;                                                                       // Show the damn thing...
803         show_which_msg = msg;                                                           // And tell it which message to show...
804 }
805
806 //
807 // Draw text message
808 //
809 void DrawText(void)
810 {
811         if (!text_life)                                                                         // Kill text if it's time
812         {
813                 show_text = false;
814                 return;
815         }
816
817         text_life--;                                                                            // Your life force is running out...
818
819         // Draw the message here...
820         DWORD scadr = hScrollOffset + voffsets[vScrollOffset] + 642;
821         WORD bmpptr = 0;
822
823         for(int y=0; y<7; y++)
824         {
825                 for(int x=0; x<21; x++)
826                 {
827                         if (show_which_msg == M60FPS)
828                         {
829                                 if (bmp1[bmpptr++] == 1)
830                                         my_scr[scadr + x + y * 320] = 7;
831                                 else
832                                         my_scr[scadr + x + y * 320] = 0;
833                         }
834                         else if (show_which_msg == M30FPS)
835                         {
836                                 if (bmp2[bmpptr++] == 1)
837                                         my_scr[scadr + x + y * 320] = 7;
838                                 else
839                                         my_scr[scadr + x + y * 320] = 0;
840                         }
841                         else if (show_which_msg == MSNAPSHOT)
842                         {
843                                 if (bmp3[bmpptr++] == 1)
844                                         my_scr[scadr + x + y * 320] = 7;
845                                 else
846                                         my_scr[scadr + x + y * 320] = 0;
847                         }
848                 }
849         }
850
851         if (show_which_msg == MSHOWNUMS)
852                 ShowNumbers(snd_num);
853 }
854
855 //
856 // Sound stuff (Will go elsewhere??? Perhaps in sound.cpp?)
857 //
858 void SpawnSound(int type, int snd, int channel/* = 0*/)
859 {
860         extern DWORD psg_lens[16];
861         extern BYTE * psg_adrs[16];
862         extern DWORD voc_lens[32];
863         extern BYTE * voc_adrs[32];
864         extern DWORD fm_lens[14];
865         extern BYTE * fm_adrs[14];
866
867         snd_num = snd;
868         SpawnMsg(MSHOWNUMS);
869
870         if (type == GAMESOUND)
871         {
872                 snd--;                                                                                  // Will that do it???  Yes!!!
873
874                 if (channel == 0)
875                 {
876                         // 00 nn ss (nn # of repeats of sample ss)
877                         DWORD st = 0;
878
879                         if (snd & 0x40)
880                         {
881                                 st = 0x10000;
882                                 snd &= 0x0F;
883                         }
884
885                         spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
886                         spos1 += st;                                                            // Need to add start somewhere...
887                         prevSamp1 = 128;
888                         sample1 = 0;
889                         chan1_go = true;
890                 }
891                 else
892                 {
893                         DWORD st = 0;
894
895                         if (snd & 0x40)
896                         {
897                                 st = 0x10000;
898                                 snd &= 0x0F;
899                         }
900
901                         spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
902                         spos2 += st;                                                            // Need to add start somewhere...
903                         prevSamp2 = 128;
904                         sample2 = 0;
905                         chan2_go = true;
906                 }
907         }
908         else if (type == PSGSOUND)
909         {
910                 if (snd_num & 0x10)                                                             // Second channel?
911                 {
912                         spos3 = 0;
913                         end_pos3 = psg_lens[snd_num & 0x0F];
914                         sndp3 = psg_adrs[snd_num & 0x0F];
915                         chan3_go = true;
916
917                         if (spos3 == end_pos3)
918                                 chan3_go = false;                                               // No sound loaded, so don't do it!
919                 }
920                 else                                                                                    // First channel
921                 {
922                         spos4 = 0;
923                         end_pos4 = psg_lens[snd_num & 0x0F];
924                         sndp4 = psg_adrs[snd_num & 0x0F];
925                         chan4_go = true;
926
927                         if (spos4 == end_pos4)
928                                 chan4_go = false;                                               // No sound loaded, so don't do it!
929                 }
930         }
931         else if (type == FMSOUND)
932         {
933                 spos5 = 0;
934                 end_pos5 = fm_lens[snd_num];
935                 sndp5 = fm_adrs[snd_num];
936                 chan5_go = true;
937
938                 if (spos5 == end_pos5)
939                         chan5_go = false;                                                       // No sound loaded, so don't do it!
940         }
941         else if (type == USERSOUND)
942         {
943                 spos6 = 0;
944                 end_pos6 = snd_lens[snd_num];                                   // User sound
945                 sndp6 = snd_array[snd_num];                                             // Load pointer
946                 chan6_go = true;
947         }
948 }
949
950 //
951 // Sound card IRQ handler
952 //
953 void SoundFunc(void * userdata, Uint8 * buff, int num)
954 {
955         uint16 cnt = 0, sample;                                                         // 0-22 different sounds...
956         uint8 start_samp1, end_samp1, start_samp2, end_samp2;
957         uint8 samp1 = 128, samp2 = 128, samp3 = 128,
958                 samp4 = 128, samp5 = 128, samp6 = 128;                  // Zero samples...
959
960         memset(buff, 128, num);                                                         // Kill sound...
961
962         if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go)
963         {
964                 while (cnt != num)
965                 {
966                         if (chan1_go)
967                         {
968                                 if (sample1 < 1)
969                                 {
970                                         samp1 = voice_rom[spos1++];
971
972                                         if (samp1 == 0xFF)
973                                         {
974                                                 chan1_go = false;
975                                                 samp1 = 128;                                    // Kill channel 1 if done...
976                                         }
977                                         else if (samp1 == 0x00)                         // RLE compression...
978                                         {
979                                                 sample1 += (float)voice_rom[spos1++] * sampleBase;      // # of repeats
980                                                 samp1   = prevSamp1;                    // Get last good sample
981                                         }
982                                         else
983                                                 sample1 += sampleBase;                  // Keep fractional part intact
984                                 }
985
986                                 prevSamp1 = samp1;                                              // Save last sample value
987                                 sample1 -= 1.0;                                                 // Decrement repeat counter
988                         }
989
990 // Stretching 5KHz samples to 22KHz:
991 //   numRepeats = 4;
992 //            6KHz -> 22KHz:  22/6 repeats...
993                         if (chan2_go)
994                         {
995                                 if (sample2 < 1)
996                                 {
997                                         samp2 = voice_rom[spos2++];
998
999                                         if (samp2 == 0xFF)
1000                                         {
1001                                                 chan2_go = false;
1002                                                 samp2 = 128;                                    // Kill channel 2 if done...
1003                                         }
1004                                         else if (samp2 == 0x00)                         // RLE compression...
1005                                         {
1006                                                 sample2 += (float)voice_rom[spos2++] * sampleBase;      // # of repeats
1007                                                 samp2   = prevSamp2;
1008                                         }
1009                                         else
1010                                                 sample2 += sampleBase;
1011                                 }
1012
1013 // Delta-X values were making the samples sound like crap...
1014 //                              start_samp2 += delta_x2;
1015                                 prevSamp2 = samp2;
1016                                 sample2 -= 1.0;
1017                         }
1018
1019       if (chan3_go)
1020       {
1021         samp3 = sndp3[spos3++];
1022         if (spos3 == end_pos3)
1023         {
1024           chan3_go = false;  samp3 = 128; // Kill channel 3 if done...
1025         }
1026       }
1027
1028       if (chan4_go)
1029       {
1030         samp4 = sndp4[spos4++];
1031         if (spos4 == end_pos4)
1032         {
1033           chan4_go = false;  samp4 = 128; // Kill channel 4 if done...
1034         }
1035       }
1036
1037       if (chan5_go)
1038       {
1039         samp5 = sndp5[spos5++];
1040         if (spos5 == end_pos5)
1041         {
1042           chan5_go = false;  samp5 = 128; // Kill channel 5 if done...
1043         }
1044       }
1045
1046                         if (chan6_go)
1047                         {
1048                                 samp6 = sndp6[spos6++];
1049
1050                                 if (spos6 == end_pos6)
1051                                         chan6_go = false, samp6 = 128;          // Kill channel 6...
1052                         }
1053
1054                         sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640;   // Mix 'em...
1055
1056                         if (sample & 0xFF00)                                            // i.e., it overflowed
1057                                 sample = (sample&0x8000 ? 0x00 : 0xFF); // Clip it
1058
1059                         buff[cnt++] = sample;                                           // & store it...
1060                 }
1061         }
1062 }