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