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