OSDN Git Service

ハャ、ォ、熙荀ケ、、、隍ヲ、ヒ。「rand_int()、andint0()。「randint()、andint1()、ヒ、ケ、ル、ニテヨ、ュハム、ィ、ソ。」
[hengband/hengband.git] / src / main-dos.c
1 /* File: main-dos.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, Robert Ruehlmann, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11
12 /*
13  * This file helps Angband work with DOS computers.
14  *
15  * Adapted from "main-ibm.c".
16  *
17  * Author: Robert Ruehlmann (rr9@angband.org).
18  * See "http://thangorodrim.angband.org/".
19  *
20  * Initial framework (and some code) by Ben Harrison (benh@phial.com).
21  *
22  * This file requires the (free) DJGPP compiler (based on "gcc").
23  * See "http://www.delorie.com/djgpp/".
24  *
25  * This file uses the (free) "Allegro" library (SVGA graphics library).
26  * See "http://www.talula.demon.co.uk/allegro/".
27  *
28  * To compile this file, use "Makefile.dos", which defines "USE_DOS".
29  *
30  * See also "main-ibm.c" and "main-win.c".
31  *
32  *
33  * The "lib/user/pref.prf" file contains macro definitions and possible
34  * alternative color set definitions.
35  *
36  * The "lib/user/font.prf" contains attr/char mappings for use with the
37  * special fonts in the "lib/xtra/font/" directory.
38  *
39  * The "lib/user/graf.prf" contains attr/char mappings for use with the
40  * special bitmaps in the "lib/xtra/graf/" directory.
41  *
42  *
43  * Both "shift" keys are treated as "identical", and all the modifier keys
44  * (control, shift, alt) are ignored when used with "normal" keys, unless
45  * they modify the underlying "ascii" value of the key.  You must use the
46  * new "user pref files" to be able to interact with the keypad and such.
47  *
48  * Note that "Term_xtra_dos_react()" allows runtime color, graphics,
49  * screen resolution, and sound modification.
50  *
51  *
52  * The sound code uses *.wav files placed in the "lib/xtra/sound" folder.
53  * Every sound-event can have several samples assigned to it and a random
54  * one will be played when the event occures. Look at the
55  * "lib/xtra/sound/sound.cfg" configuration file for more informations.
56  *
57  * The background music uses midi-files (and mod files) from the
58  * "lib/xtra/music" folder.
59  *
60  *
61  * Comment by Ben Harrison (benh@phial.com):
62  *
63  * On my Windows NT box, modes "VESA1" and "VESA2B" seem to work, but
64  * result in the game running with no visible output.  Mode "VESA2L"
65  * clears the screen and then fails silently.  All other modes fail
66  * instantly.  To recover from such "invisible" modes, you can try
67  * typing escape, plus control-x, plus escape.  XXX XXX XXX
68  */
69
70 #include "angband.h"
71
72
73 #ifdef USE_DOS
74
75 #include <allegro.h>
76
77 #ifdef USE_MOD_FILES
78 #include <jgmod.h>
79 #endif /* USE_MOD_FILES */
80
81 #include <bios.h>
82 #include <dos.h>
83 #include <keys.h>
84 #include <unistd.h>
85 #include <dir.h>
86
87 /*
88  * Index of the first standard Angband color.
89  *
90  * All colors below this index are defined by
91  * the palette of the tiles-bitmap.
92  */
93 #define COLOR_OFFSET 240
94
95
96 /*
97  * Maximum number of terminals
98  */
99 #define MAX_TERM_DATA 8
100
101
102 /*
103  * Forward declare
104  */
105 typedef struct term_data term_data;
106
107
108 /*
109  * Extra "term" data
110  */
111 struct term_data
112 {
113         term t;
114
115         int number;
116
117         int x;
118         int y;
119
120         int cols;
121         int rows;
122
123         int tile_wid;
124         int tile_hgt;
125
126         int font_wid;
127         int font_hgt;
128
129         FONT *font;
130
131 #ifdef USE_GRAPHICS
132
133         BITMAP *tiles;
134
135 #endif /* USE_GRAPHICS */
136
137 #ifdef USE_BACKGROUND
138
139         int window_type;
140
141 #endif /* USE_BACKGROUND */
142
143 };
144
145 /*
146  * The current screen resolution
147  */
148 static int resolution;
149
150 #ifdef USE_BACKGROUND
151
152 /*
153  * The background images
154  */
155 BITMAP *background[17];
156
157 #endif /* USE_BACKGROUND */
158
159
160 /*
161  * An array of term_data's
162  */
163 static term_data data[MAX_TERM_DATA];
164
165
166 #ifdef USE_GRAPHICS
167
168 /*
169  * Are graphics already initialized ?
170  */
171 static bool graphics_initialized = FALSE;
172
173 #endif /* USE_GRAPHICS */
174
175
176 /*
177  * Small bitmap for the cursor
178  */
179 static BITMAP *cursor;
180
181
182 #ifdef USE_SOUND
183
184 /*
185  * Is the sound already initialized ?
186  */
187 static bool sound_initialized = FALSE;
188
189 # ifdef USE_MOD_FILES
190 /*
191  * Is the mod-file support already initialized ?
192  */
193 static bool mod_file_initialized = FALSE;
194
195 # endif /* USE_MOD_FILES */
196
197 /*
198  * Volume settings
199  */
200 static int digi_volume;
201 static int midi_volume;
202
203 /*
204  * The currently playing song
205  */
206 static MIDI *midi_song = NULL;
207
208 # ifdef USE_MOD_FILES
209
210 static JGMOD *mod_song = NULL;
211
212 # endif /* USE_MOD_FILES */
213
214 static int current_song;
215
216 /*
217  * The number of available songs
218  */
219 static int song_number;
220
221 /*
222  * The maximum number of available songs
223  */
224 #define MAX_SONGS 255
225
226 static char music_files[MAX_SONGS][16];
227
228 /*
229  * The maximum number of samples per sound-event
230  */
231 #define SAMPLE_MAX 10
232
233 /*
234  * An array of sound files
235  */
236 static SAMPLE* samples[SOUND_MAX][SAMPLE_MAX];
237
238 /*
239  * The number of available samples for every event
240  */
241 static int sample_count[SOUND_MAX];
242
243 #endif /* USE_SOUND */
244
245
246 /*
247  *  Extra paths
248  */
249 static char xtra_font_dir[1024];
250 static char xtra_graf_dir[1024];
251 static char xtra_sound_dir[1024];
252 static char xtra_music_dir[1024];
253
254 /*
255  * List of used videomodes to reduce executable size
256  */
257 BEGIN_GFX_DRIVER_LIST
258         GFX_DRIVER_VBEAF
259         GFX_DRIVER_VGA
260         GFX_DRIVER_VESA3
261         GFX_DRIVER_VESA2L
262         GFX_DRIVER_VESA2B
263         GFX_DRIVER_VESA1
264 END_GFX_DRIVER_LIST
265
266
267 /*
268  * List of used color depths to reduce executeable size
269  */
270 BEGIN_COLOR_DEPTH_LIST
271         COLOR_DEPTH_8
272 END_COLOR_DEPTH_LIST
273
274
275 /*
276  * Keypress input modifier flags (hard-coded by DOS)
277  */
278 #define K_RSHIFT        0       /* Right shift key down */
279 #define K_LSHIFT        1       /* Left shift key down */
280 #define K_CTRL          2       /* Ctrl key down */
281 #define K_ALT           3       /* Alt key down */
282 #define K_SCROLL        4       /* Scroll lock on */
283 #define K_NUM           5       /* Num lock on */
284 #define K_CAPS          6       /* Caps lock on */
285 #define K_INSERT        7       /* Insert on */
286
287
288 /*
289  * Prototypes
290  */
291 static errr Term_xtra_dos_event(int v);
292 static void Term_xtra_dos_react(void);
293 static void Term_xtra_dos_clear(void);
294 static errr Term_xtra_dos(int n, int v);
295 static errr Term_user_dos(int n);
296 static errr Term_curs_dos(int x, int y);
297 static errr Term_wipe_dos(int x, int y, int n);
298 static errr Term_text_dos(int x, int y, int n, byte a, const char *cp);
299 static void Term_init_dos(term *t);
300 static void Term_nuke_dos(term *t);
301 static void term_data_link(term_data *td);
302 static void dos_dump_screen(void);
303 static void dos_quit_hook(cptr str);
304 static bool init_windows(void);
305 errr init_dos(void);
306 #ifdef USE_SOUND
307 static bool init_sound(void);
308 static errr Term_xtra_dos_sound(int v);
309 static void play_song(void);
310 #endif /* USE_SOUND */
311 #ifdef USE_GRAPHICS
312 static bool init_graphics(void);
313 # ifdef USE_TRANSPARENCY
314 static errr Term_pict_dos(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp);
315 # else /* USE_TRANSPARENCY */
316 static errr Term_pict_dos(int x, int y, int n, const byte *ap, const char *cp);
317 # endif /* USE_TRANSPARENCY */
318 #endif /* USE_GRAPHICS */
319
320
321 /*
322  * Process an event (check for a keypress)
323  *
324  * The keypress processing code is often the most system dependant part
325  * of Angband, since sometimes even the choice of compiler is important.
326  *
327  * For this file, we divide all keypresses into two catagories, first, the
328  * "normal" keys, including all keys required to play Angband, and second,
329  * the "special" keys, such as keypad keys, function keys, and various keys
330  * used in combination with various modifier keys.
331  *
332  * To simplify this file, we use Angband's "macro processing" ability, in
333  * combination with the "lib/user/pref.prf" file, to handle most of the
334  * "special" keys, instead of attempting to fully analyze them here.  This
335  * file only has to determine when a "special" key has been pressed, and
336  * translate it into a simple string which signals the use of a "special"
337  * key, the set of modifiers used, if any, and the hardware scan code of
338  * the actual key which was pressed.  To simplify life for the user, we
339  * treat both "shift" keys as identical modifiers.
340  *
341  * The final encoding is "^_MMMxSS\r", where "MMM" encodes the modifiers
342  * ("C" for control, "S" for shift, "A" for alt, or any ordered combination),
343  * and "SS" encodes the keypress (as the two "digit" hexidecimal encoding of
344  * the scan code of the key that was pressed), and the "^_" and "x" and "\r"
345  * delimit the encoding for recognition by the macro processing code.
346  *
347  * Some important facts about scan codes follow.  All "normal" keys use
348  * scan codes from 1-58.  The "function" keys use 59-68 (and 133-134).
349  * The "keypad" keys use 69-83.  Escape uses 1.  Enter uses 28.  Control
350  * uses 29.  Left Shift uses 42.  Right Shift uses 54.  PrtScrn uses 55.
351  * Alt uses 56.  Space uses 57.  CapsLock uses 58.  NumLock uses 69.
352  * ScrollLock uses 70.  The "keypad" keys which use scan codes 71-83
353  * are ordered KP7,KP8,KP9,KP-,KP4,KP5,KP6,KP+,KP1,KP2,KP3,INS,DEL.
354  *
355  * Using "bioskey(0x10)" instead of "bioskey(0)" apparently provides more
356  * information, including better access to the keypad keys in combination
357  * with various modifiers, but only works on "PC's after 6/1/86", and there
358  * is no way to determine if the function is provided on a machine.  I have
359  * been told that without it you cannot detect, for example, control-left.
360  * The basic scan code + ascii value pairs returned by the keypad follow,
361  * with values in parentheses only available to "bioskey(0x10)".
362  *
363  *         /      *      -      +      1      2      3      4
364  * Norm:  352f   372a   4a2d   4e2b   4f00   5000   5100   4b00
365  * Shft:  352f   372a   4a2d   4e2b   4f31   5032   5133   4b34
366  * Ctrl: (9500) (9600) (8e00) (9000)  7500  (9100)  7600   7300
367  *
368  *         5      6      7      8      9      0      .     Enter
369  * Norm: (4c00)  4d00   4700   4800   4900   5200   5300  (e00d)
370  * Shft:  4c35   4d36   4737   4838   4939   5230   532e  (e00d)
371  * Ctrl: (8f00)  7400   7700  (8d00)  8400  (9200) (9300) (e00a)
372  *
373  * See "lib/user/pref-win.prf" for the "standard" macros for various keys.
374  *
375  * Certain "bizarre" keypad keys (such as "enter") return a "scan code"
376  * of "0xE0", and a "usable" ascii value.  These keys should be treated
377  * like the normal keys, see below.  XXX XXX XXX Note that these "special"
378  * keys could be prefixed with an optional "ctrl-^" which would allow them
379  * to be used in macros without hurting their use in normal situations.
380  *
381  * This function also appears in "main-ibm.c".  XXX XXX XXX
382  *
383  * Addition for the DOS version: Dump-screen function with the
384  * "Ctrl-Print" key saves a bitmap with the screen contents to
385  * "lib/user/dump.bmp".
386  */
387 static errr Term_xtra_dos_event(int v)
388 {
389         int i, k, s;
390
391         bool mc = FALSE;
392         bool ms = FALSE;
393         bool ma = FALSE;
394
395         /* Hack -- Check for a keypress */
396         if (!v && !bioskey(1)) return (1);
397
398         /* Wait for a keypress */
399         k = bioskey(0x10);
400
401         /* Access the "modifiers" */
402         i = bioskey(2);
403
404         /* Extract the "scan code" */
405         s = ((k >> 8) & 0xFF);
406
407         /* Extract the "ascii value" */
408         k = (k & 0xFF);
409
410         /* Process "normal" keys */
411         if ((s <= 58) || (s == 0xE0))
412         {
413                 /* Enqueue it */
414                 if (k) Term_keypress(k);
415
416                 /* Success */
417                 return (0);
418         }
419
420         /* Extract the modifier flags */
421         if (i & (1 << K_CTRL)) mc = TRUE;
422         if (i & (1 << K_LSHIFT)) ms = TRUE;
423         if (i & (1 << K_RSHIFT)) ms = TRUE;
424         if (i & (1 << K_ALT)) ma = TRUE;
425
426         /* Dump the screen with "Ctrl-Print" */
427         if ((s == 0x72) && mc)
428         {
429                 /* Dump the screen */
430                 dos_dump_screen();
431
432                 /* Success */
433                 return (0);
434         }
435
436         /* Begin a "macro trigger" */
437         Term_keypress(31);
438
439         /* Hack -- Send the modifiers */
440         if (mc) Term_keypress('C');
441         if (ms) Term_keypress('S');
442         if (ma) Term_keypress('A');
443
444         /* Introduce the hexidecimal scan code */
445         Term_keypress('x');
446
447         /* Encode the hexidecimal scan code */
448         Term_keypress(hexsym[s/16]);
449         Term_keypress(hexsym[s%16]);
450
451         /* End the "macro trigger" */
452         Term_keypress(13);
453
454         /* Success */
455         return (0);
456 }
457
458
459 /*
460  * React to global changes in the colors, graphics, and sound settings.
461  */
462 static void Term_xtra_dos_react(void)
463 {
464         int i;
465
466 #ifdef USE_SPECIAL_BACKGROUND
467
468         int j;
469
470         term_data *td;
471
472 #endif /* USE_SPECIAL_BACKGROUND */
473
474         /*
475          * Set the Angband colors
476          */
477         for (i = 0; i < 16; i++)
478         {
479                 /* Extract desired values */
480                 char rv = angband_color_table[i][1] >> 2;
481                 char gv = angband_color_table[i][2] >> 2;
482                 char bv = angband_color_table[i][3] >> 2;
483
484                 RGB color = { rv,  gv,  bv  };
485
486                 set_color(COLOR_OFFSET + i, &color);
487         }
488
489 #ifdef USE_GRAPHICS
490
491         /*
492          * Handle "arg_graphics"
493          */
494         if (use_graphics != arg_graphics)
495         {
496                 /* Initialize (if needed) */
497                 if (arg_graphics && !init_graphics())
498                 {
499                         /* Warning */
500                         plog("Cannot initialize graphics!");
501
502                         /* Cannot enable */
503                         arg_graphics = GRAPHICS_NONE;
504                 }
505
506                 /* Change setting */
507                 use_graphics = arg_graphics;
508         }
509
510 #endif /* USE_GRAPHICS */
511
512 #ifdef USE_SOUND
513
514         /*
515          * Handle "arg_sound"
516          */
517         if (use_sound != arg_sound)
518         {
519                 /* Clear the old song */
520                 if (midi_song) destroy_midi(midi_song);
521                 midi_song = NULL;
522
523 #ifdef USE_MOD_FILES
524                 if (mod_file_initialized)
525                 {
526                         stop_mod();
527                         destroy_mod(mod_song);
528                 }
529 #endif /* USE_MOD_FILES */
530
531                 /* Initialize (if needed) */
532                 if (arg_sound && !init_sound())
533                 {
534                         /* Warning */
535                         plog("Cannot initialize sound!");
536
537                         /* Cannot enable */
538                         arg_sound = FALSE;
539                 }
540
541                 /* Change setting */
542                 use_sound = arg_sound;
543         }
544
545 #endif /* USE_SOUND */
546
547 #ifdef USE_SPECIAL_BACKGROUND
548
549         /*
550          * Initialize the window backgrounds
551          */
552         for (i = 0; i < 8; i++)
553         {
554                 td = &data[i];
555
556                 /* Window flags */
557                 for (j = 0; j < 16; j++)
558                 {
559                         if (op_ptr->window_flag[i] & (1L << j))
560                         {
561                                 if (background[j + 1])
562                                 {
563                                         td->window_type = j + 1;
564                                 }
565                                 else
566                                 {
567                                         td->window_type = 0;
568                                 }
569                         }
570                 }
571         }
572 #endif /* USE_SPECIAL_BACKGROUND */
573 }
574
575
576 /*
577  * Clear a terminal
578  *
579  * Fills the terminal area with black color or with
580  * the background image
581  */
582 static void Term_xtra_dos_clear(void)
583 {
584         term_data *td = (term_data*)(Term->data);
585
586 #ifdef USE_BACKGROUND
587         int bgrnd;
588 #endif /* USE_BACKGROUND */
589
590         int x1, y1;
591         int w1, h1;
592
593         /* Location */
594         x1 = td->x;
595         y1 = td->y;
596
597         /* Size */
598         w1 = td->tile_wid * td->cols;
599         h1 = td->tile_hgt * td->rows;
600
601 #ifdef USE_BACKGROUND
602
603         bgrnd = td->window_type;
604
605         if (background[bgrnd])
606         {
607                 /* Draw the background */
608                 stretch_blit(background[bgrnd], screen,
609                         0, 0, background[bgrnd]->w, background[bgrnd]->h,
610                         x1, y1, w1, h1);
611         }
612         else
613
614 #endif /* USE_BACKGROUND */
615
616         {
617                 /* Draw the Term black */
618                 rectfill(screen,
619                         x1, y1, x1 + w1 - 1, y1 + h1 - 1,
620                         COLOR_OFFSET + TERM_DARK);
621         }
622 }
623
624
625 /*
626  * Handle a "special request"
627  *
628  * The given parameters are "valid".
629  */
630 static errr Term_xtra_dos(int n, int v)
631 {
632         /* Analyze the request */
633         switch (n)
634         {
635                 /* Make a "bell" noise */
636                 case TERM_XTRA_NOISE:
637                 {
638                         /* Make a bell noise */
639                         (void)write(1, "\007", 1);
640
641                         /* Success */
642                         return (0);
643                 }
644
645                 /* Clear the screen */
646                 case TERM_XTRA_CLEAR:
647                 {
648                         /* Clear the screen */
649                         Term_xtra_dos_clear();
650
651                         /* Success */
652                         return (0);
653                 }
654
655                 /* Process events */
656                 case TERM_XTRA_EVENT:
657                 {
658                         /* Process one event */
659                         return (Term_xtra_dos_event(v));
660                 }
661
662                 /* Flush events */
663                 case TERM_XTRA_FLUSH:
664                 {
665                         /* Strip events */
666                         while (!Term_xtra_dos_event(FALSE));
667
668                         /* Success */
669                         return (0);
670                 }
671
672                 /* Do something useful if bored */
673                 case TERM_XTRA_BORED:
674                 {
675 #ifdef USE_SOUND
676                         /*
677                          * Check for end of song and start a new one
678                          */
679                         if (!use_sound) return (0);
680
681 #ifdef USE_MOD_FILES
682                         if (song_number && (midi_pos == -1) && !is_mod_playing())
683 #else /* USE_MOD_FILES */
684                         if (song_number && (midi_pos == -1))
685 #endif /* USE_MOD_FILES */
686                         {
687                                 if (song_number > 1)
688                                 {
689                                         /* Get a *new* song at random */
690                                         while (1)
691                                         {
692                                                 n = randint1(song_number);
693                                                 if (n != current_song) break;
694                                         }
695                                         current_song = n;
696                                 }
697                                 else
698                                 {
699                                         /* We only have one song, so loop it */
700                                         current_song = 1;
701                                 }
702
703                                 /* Play the song */
704                                 play_song();
705                         }
706
707 #endif /* USE_SOUND */
708
709                         /* Success */
710                         return (0);
711                 }
712
713                 /* React to global changes */
714                 case TERM_XTRA_REACT:
715                 {
716                         /* Change the colors */
717                         Term_xtra_dos_react();
718
719                         /* Success */
720                         return (0);
721                 }
722
723                 /* Delay for some milliseconds */
724                 case TERM_XTRA_DELAY:
725                 {
726                         /* Delay if needed */
727                         if (v > 0) delay(v);
728
729                         /* Success */
730                         return (0);
731                 }
732
733 #ifdef USE_SOUND
734
735                 /* Make a sound */
736                 case TERM_XTRA_SOUND:
737                 {
738                         return (Term_xtra_dos_sound(v));
739                 }
740
741 #endif /* USE_SOUND */
742
743         }
744
745         /* Unknown request */
746         return (1);
747 }
748
749
750 /*
751  * Do a "user action" on the current "term"
752  */
753 static errr Term_user_dos(int n)
754 {
755         int k;
756
757         char status[4];
758
759         char section[80];
760
761         /* Interact */
762         while (1)
763         {
764                 /* Clear screen */
765                 Term_clear();
766
767                 /* Print date and time of compilation */
768                 prt(format("Compiled: %s %s\n", __TIME__, __DATE__), 1, 45);
769
770                 /* Why are we here */
771                 prt("DOS options", 2, 0);
772
773                 /* Give some choices */
774 #ifdef USE_SOUND
775                 prt("(V) Sound Volume", 4, 5);
776                 prt("(M) Music Volume", 5, 5);
777 #endif /* USE_SOUND */
778
779 #ifdef USE_GRAPHICS
780
781                 if (arg_graphics)
782                 {
783                         strcpy(status, "On");
784                 }
785                 else
786                 {
787                         strcpy(status, "Off");
788                 }
789                 prt(format("(G) Graphics : %s", status), 7, 5);
790
791 #endif /* USE_GRAPHICS */
792
793 #ifdef USE_SOUND
794
795                 if (arg_sound)
796                 {
797                         strcpy(status, "On");
798                 }
799                 else
800                 {
801                         strcpy(status, "Off");
802                 }
803                 prt(format("(S) Sound/Music : %s", status), 8, 5);
804
805 #endif /* USE_SOUND */
806
807                 prt("(R) Screen resolution", 12, 5);
808
809                 prt("(W) Save current options", 14, 5);
810
811                 /* Prompt */
812                 prt("Command: ", 18, 0);
813
814                 /* Get command */
815                 k = inkey();
816
817                 /* Exit */
818                 if (k == ESCAPE) break;
819
820                 /* Analyze */
821                 switch (k)
822                 {
823 #ifdef USE_SOUND
824                         /* Sound Volume */
825                         case 'V':
826                         case 'v':
827                         {
828                                 /* Prompt */
829                                 prt("Command: Sound Volume", 18, 0);
830
831                                 /* Get a new value */
832                                 while (1)
833                                 {
834                                         prt(format("Current Volume: %d", digi_volume), 22, 0);
835                                         prt("Change Volume (+, - or ESC to accept): ", 20, 0);
836                                         k = inkey();
837                                         if (k == ESCAPE) break;
838                                         switch (k)
839                                         {
840                                                 case '+':
841                                                 {
842                                                         digi_volume++;
843                                                         if (digi_volume > 255) digi_volume = 255;
844                                                         break;
845                                                 }
846                                                 case '-':
847                                                 {
848                                                         digi_volume--;
849                                                         if (digi_volume < 0) digi_volume = 0;
850                                                         break;
851                                                 }
852                                                 /* Unknown option */
853                                                 default:
854                                                 {
855                                                         break;
856                                                 }
857                                         }
858                                         set_volume(digi_volume, -1);
859                                 }
860                                 break;
861                         }
862
863                         /* Music Volume */
864                         case 'M':
865                         case 'm':
866                         {
867                                 /* Prompt */
868                                 prt("Command: Music Volume", 18, 0);
869
870                                 /* Get a new value */
871                                 while (1)
872                                 {
873                                         prt(format("Current Volume: %d", midi_volume), 22, 0);
874                                         prt("Change Volume (+, - or ESC to accept): ", 20, 0);
875                                         k = inkey();
876                                         if (k == ESCAPE) break;
877                                         switch (k)
878                                         {
879                                                 case '+':
880                                                 {
881                                                         midi_volume++;
882                                                         if (midi_volume > 255) midi_volume = 255;
883                                                         break;
884                                                 }
885                                                 case '-':
886                                                 {
887                                                         midi_volume--;
888                                                         if (midi_volume < 0) midi_volume = 0;
889                                                         break;
890                                                 }
891                                                 /* Unknown option */
892                                                 default:
893                                                 {
894                                                         break;
895                                                 }
896                                         }
897                                         set_volume(-1, midi_volume);
898                                 }
899                                 break;
900                         }
901
902 #endif /* USE_SOUND */
903
904 #ifdef USE_GRAPHICS
905
906                         /* Switch graphics on/off */
907                         case 'G':
908                         case 'g':
909                         {
910                                 /* Toggle "arg_graphics" */
911                                 arg_graphics = !arg_graphics;
912
913                                 /* React to changes */
914                                 Term_xtra_dos_react();
915
916                                 /* Reset visuals */
917 #ifdef ANGBAND_2_8_1
918                                 reset_visuals();
919 #else /* ANGBAND_2_8_1 */
920                                 reset_visuals(TRUE);
921 #endif /* ANGBAND_2_8_1 */
922                                 break;
923                         }
924
925 #endif /* USE_GRAPHICS */
926
927 #ifdef USE_SOUND
928
929                         /* Sound/Music On/Off */
930                         case 'S':
931                         case 's':
932                         {
933                                 /* Toggle "arg_sound" */
934                                 arg_sound = !arg_sound;
935
936                                 /* React to changes */
937                                 Term_xtra_dos_react();
938
939                                 break;
940                         }
941
942 #endif /* USE_SOUND */
943
944                         /* Screen Resolution */
945                         case 'R':
946                         case 'r':
947                         {
948                                 int h, w, i = 1;
949                                 char *descr;
950
951                                 /* Clear screen */
952                                 Term_clear();
953
954                                 /* Prompt */
955                                 prt("Command: Screen Resolution", 1, 0);
956                                 prt("Restart Angband to get the new screenmode.", 3, 0);
957
958                                 /* Get a list of the available presets */
959                                 while (1)
960                                 {
961                                         /* Section name */
962                                         sprintf(section, "Mode-%d", i);
963
964                                         /* Get new values or end the list */
965                                         if (!(w = get_config_int(section, "screen_wid", 0)) || (i == 16)) break;
966                                         h = get_config_int(section, "screen_hgt", 0);
967
968                                         /* Get a extra description of the resolution */
969                                         descr = get_config_string(section, "Description", "");
970
971                                         /* Print it */
972                                         prt(format("(%d) %d x %d   %s", i, w, h, descr), 4 + i, 0);
973
974                                         /* Next */
975                                         i++;
976                                 }
977
978                                 /* Get a new resolution */
979                                 prt(format("Screen Resolution : %d", resolution), 20, 0);
980                                 k = inkey();
981                                 if (k == ESCAPE) break;
982                                 if (isdigit(k)) resolution = D2I(k);
983
984                                 /* Check for min, max value */
985                                 if ((resolution < 1) || (resolution >= i)) resolution = 1;
986
987                                 /* Save the resolution */
988                                 set_config_int("Angband", "Resolution", resolution);
989
990                                 /* Return */
991                                 break;
992                         }
993
994
995                         /* Save current option */
996                         case 'W':
997                         case 'w':
998                         {
999                                 prt("Saving current options", 18, 0);
1000
1001 #ifdef USE_SOUND
1002                                 set_config_int("sound", "digi_volume", digi_volume);
1003                                 set_config_int("sound", "midi_volume", midi_volume);
1004 #endif /* USE_SOUND */
1005                                 set_config_int("Angband", "Graphics", arg_graphics);
1006                                 set_config_int("Angband", "Sound", arg_sound);
1007
1008                                 break;
1009                         }
1010
1011                         /* Unknown option */
1012                         default:
1013                         {
1014                                 break;
1015                         }
1016                 }
1017
1018                 /* Flush messages */
1019                 msg_print(NULL);
1020         }
1021
1022         /* Redraw it */
1023         Term_key_push(KTRL('R'));
1024
1025         /* Unknown */
1026         return (0);
1027 }
1028
1029
1030 /*
1031  * Move the cursor
1032  *
1033  * The given parameters are "valid".
1034  */
1035 static errr Term_curs_dos(int x, int y)
1036 {
1037         term_data *td = (term_data*)(Term->data);
1038
1039         int x1, y1;
1040
1041         /* Location */
1042         x1 = x * td->tile_wid + td->x;
1043         y1 = y * td->tile_hgt + td->y;
1044
1045         /* Draw the cursor */
1046         draw_sprite(screen, cursor, x1, y1);
1047
1048         /* Success */
1049         return (0);
1050 }
1051
1052
1053 /*
1054  * Erase a block of the screen
1055  *
1056  * The given parameters are "valid".
1057  */
1058 static errr Term_wipe_dos(int x, int y, int n)
1059 {
1060         term_data *td = (term_data*)(Term->data);
1061
1062 #ifdef USE_BACKGROUND
1063         int bgrnd;
1064 #endif /* USE_BACKGROUND */
1065
1066         int x1, y1;
1067         int w1, h1;
1068
1069         /* Location */
1070         x1 = x * td->tile_wid + td->x;
1071         y1 = y * td->tile_hgt + td->y;
1072
1073         /* Size */
1074         w1 = n * td->tile_wid;
1075         h1 = td->tile_hgt;
1076
1077 #ifdef USE_BACKGROUND
1078
1079         bgrnd = td->window_type;
1080
1081         if (background[bgrnd])
1082         {
1083                 int source_x = x * background[bgrnd]->w / td->cols;
1084                 int source_y = y * background[bgrnd]->h / td->rows;
1085                 int source_w = n * background[bgrnd]->w / td->cols;
1086                 int source_h = background[bgrnd]->h / td->rows;
1087
1088                 /* Draw the background */
1089                 stretch_blit(background[bgrnd], screen,
1090                         source_x, source_y, source_w, source_h,
1091                         x1, y1, w1, h1);
1092         }
1093         else
1094
1095 #endif /* USE_BACKGROUND */
1096
1097         {
1098                 /* Draw a black block */
1099                 rectfill(screen, x1, y1, x1 + w1 - 1, y1 + h1 - 1,
1100                         COLOR_OFFSET + TERM_DARK);
1101         }
1102
1103         /* Success */
1104         return (0);
1105 }
1106
1107
1108 /*
1109  * Place some text on the screen using an attribute
1110  *
1111  * The given parameters are "valid".  Be careful with "a".
1112  *
1113  * The string "cp" has length "n" and is NOT null-terminated.
1114  */
1115 static errr Term_text_dos(int x, int y, int n, byte a, const char *cp)
1116 {
1117         term_data *td = (term_data*)(Term->data);
1118
1119         int i;
1120
1121         int x1, y1;
1122
1123         char text[257];
1124
1125         /* Location */
1126         x1 = x * td->tile_wid + td->x;
1127         y1 = y * td->tile_hgt + td->y;
1128
1129         /* Erase old contents */
1130         Term_wipe_dos(x, y, n);
1131
1132 #ifdef USE_SPECIAL_BACKGROUND
1133
1134         /* Show text in black in the message window */
1135         if (op_ptr->window_flag[td->number] & (PW_MESSAGE)) a = 0;
1136
1137 #endif /* USE_SPECIAL_BACKGROUND */
1138
1139         /* No stretch needed */
1140         if (td->font_wid == td->tile_wid)
1141         {
1142                 /* Copy the string */
1143                 for (i = 0; i < n; ++i) text[i] = cp[i];
1144
1145                 /* Terminate */
1146                 text[i] = '\0';
1147
1148                 /* Dump the text */
1149                 textout(screen, td->font, text, x1, y1,
1150                         COLOR_OFFSET + (a & 0x0F));
1151         }
1152         /* Stretch needed */
1153         else
1154         {
1155                 /* Pre-Terminate */
1156                 text[1] = '\0';
1157
1158                 /* Write the chars to the screen */
1159                 for (i = 0; i < n; ++i)
1160                 {
1161                         /* Build a one character string */
1162                         text[0] = cp[i];
1163
1164                         /* Dump some text */
1165                         textout(screen, td->font, text, x1, y1,
1166                                 COLOR_OFFSET + (a & 0x0F));
1167
1168                         /* Advance */
1169                         x1 += td->tile_wid;
1170                 }
1171         }
1172
1173         /* Success */
1174         return (0);
1175 }
1176
1177
1178 #ifdef USE_GRAPHICS
1179
1180 /*
1181  * Place some attr/char pairs on the screen
1182  *
1183  * The given parameters are "valid".
1184  *
1185  * To prevent crashes, we must not only remove the high bits of the
1186  * "ap[i]" and "cp[i]" values, but we must map the resulting value
1187  * onto the legal bitmap size, which is normally 32x32.  XXX XXX XXX
1188  */
1189 #ifdef USE_TRANSPARENCY
1190 static errr Term_pict_dos(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp)
1191 #else /* USE_TRANSPARENCY */
1192 static errr Term_pict_dos(int x, int y, int n, const byte *ap, const char *cp)
1193 #endif /* USE_TRANSPARENCY */
1194 {
1195         term_data *td = (term_data*)(Term->data);
1196
1197         int i;
1198
1199         int w, h;
1200
1201         int x1, y1;
1202         int x2, y2;
1203
1204 # ifdef USE_TRANSPARENCY
1205
1206         int x3, y3;
1207
1208 # endif /* USE_TRANSPARENCY */
1209
1210         /* Size */
1211         w = td->tile_wid;
1212         h = td->tile_hgt;
1213
1214         /* Location (window) */
1215         x1 = x * w + td->x;
1216         y1 = y * h + td->y;
1217
1218         /* Dump the tiles */
1219         for (i = 0; i < n; i++)
1220         {
1221                 /* Location (bitmap) */
1222                 x2 = (cp[i] & 0x7F) * w;
1223                 y2 = (ap[i] & 0x7F) * h;
1224
1225 # ifdef USE_TRANSPARENCY
1226                 x3 = (tcp[i] & 0x7F) * w;
1227                 y3 = (tap[i] & 0x7F) * h;
1228
1229                 /* Blit the tile to the screen */
1230                 blit(td->tiles, screen, x3, y3, x1, y1, w, h);
1231
1232                 /* Blit the tile to the screen */
1233                 masked_blit(td->tiles, screen, x2, y2, x1, y1, w, h);
1234
1235 # else /* USE_TRANSPARENCY */
1236
1237                 /* Blit the tile to the screen */
1238                 blit(td->tiles, screen, x2, y2, x1, y1, w, h);
1239
1240 # endif /* USE_TRANSPARENCY */
1241
1242                 /* Advance (window) */
1243                 x1 += w;
1244         }
1245
1246         /* Success */
1247         return (0);
1248 }
1249
1250 #endif /* USE_GRAPHICS */
1251
1252
1253 /*
1254  * Init a Term
1255  */
1256 static void Term_init_dos(term *t)
1257 {
1258         /* XXX Nothing */
1259 }
1260
1261
1262 /*
1263  * Nuke a Term
1264  */
1265 static void Term_nuke_dos(term *t)
1266 {
1267         term_data *td = (term_data*)(t->data);
1268
1269         /* Free the terminal font */
1270         if (td->font) destroy_font(td->font);
1271
1272 #ifdef USE_GRAPHICS
1273
1274         /* Free the terminal bitmap */
1275         if (td->tiles) destroy_bitmap(td->tiles);
1276
1277 #endif /* USE_GRAPHICS */
1278 }
1279
1280
1281
1282 /*
1283  * Instantiate a "term_data" structure
1284  */
1285 static void term_data_link(term_data *td)
1286 {
1287         term *t = &td->t;
1288
1289         /* Initialize the term */
1290         term_init(t, td->cols, td->rows, 255);
1291
1292         /* Use a "software" cursor */
1293         t->soft_cursor = TRUE;
1294
1295         /* Ignore the "TERM_XTRA_BORED" action */
1296         t->never_bored = FALSE;
1297
1298         /* Ignore the "TERM_XTRA_FROSH" action */
1299         t->never_frosh = TRUE;
1300
1301         /* Erase with "white space" */
1302         t->attr_blank = TERM_WHITE;
1303         t->char_blank = ' ';
1304
1305         /* Prepare the init/nuke hooks */
1306         t->init_hook = Term_init_dos;
1307         t->nuke_hook = Term_nuke_dos;
1308
1309         /* Prepare the template hooks */
1310         t->xtra_hook = Term_xtra_dos;
1311         t->curs_hook = Term_curs_dos;
1312         t->wipe_hook = Term_wipe_dos;
1313         t->user_hook = Term_user_dos;
1314         t->text_hook = Term_text_dos;
1315
1316 #ifdef USE_GRAPHICS
1317
1318         /* Prepare the graphics hook */
1319         t->pict_hook = Term_pict_dos;
1320
1321         /* Use "Term_pict" for "graphic" data */
1322         t->higher_pict = TRUE;
1323
1324 #endif /* USE_GRAPHICS */
1325
1326         /* Remember where we came from */
1327         t->data = (vptr)(td);
1328 }
1329
1330
1331 /*
1332  * Shut down visual system, then fall back into standard "quit()"
1333  */
1334 static void dos_quit_hook(cptr str)
1335 {
1336         int i;
1337
1338         /* Destroy sub-windows */
1339         for (i = MAX_TERM_DATA - 1; i >= 1; i--)
1340         {
1341                 /* Unused */
1342                 if (!angband_term[i]) continue;
1343
1344                 /* Nuke it */
1345                 term_nuke(angband_term[i]);
1346         }
1347
1348
1349         /* Free all resources */
1350         if (cursor) destroy_bitmap(cursor);
1351
1352 #ifdef USE_BACKGROUND
1353
1354         /* Free the background bitmaps */
1355         for (i = 0; i < 17; i++)
1356         {
1357                 if (background[i]) destroy_bitmap(background[i]);
1358         }
1359
1360 #endif /* USE_BACKGROUND */
1361
1362
1363 #ifdef USE_SOUND
1364
1365         if (sound_initialized)
1366         {
1367                 /* Destroy samples */
1368                 for (i = 1; i < SOUND_MAX; i++)
1369                 {
1370                         int j;
1371
1372                         for (j = 0; j < sample_count[i]; j++)
1373                         {
1374                                 if (samples[i][j]) destroy_sample(samples[i][j]);
1375                         }
1376                 }
1377         }
1378
1379         /* Clear the old song */
1380         if (midi_song) destroy_midi(midi_song);
1381         midi_song =NULL;
1382 # ifdef USE_MOD_FILES
1383         if (mod_file_initialized)
1384         {
1385                 stop_mod();
1386                 destroy_mod(mod_song);
1387         }
1388 # endif /* USE_MOD_FILES */
1389
1390 #endif /* USE_SOUND */
1391
1392         /* Shut down Allegro */
1393         allegro_exit();
1394 }
1395
1396
1397 /*
1398  * Dump the screen to "lib/user/dump.bmp"
1399  */
1400 static void dos_dump_screen(void)
1401 {
1402         /* Bitmap and palette of the screen */
1403         BITMAP *bmp;
1404         PALETTE pal;
1405
1406         /* Filename */
1407         char filename[1024];
1408
1409         /* Get bitmap and palette of the screen */
1410         bmp = create_sub_bitmap(screen, 0, 0, SCREEN_W, SCREEN_H);
1411         get_palette(pal);
1412
1413         /* Build the filename for the screen-dump */
1414         path_build(filename, 1024, ANGBAND_DIR_USER, "dump.bmp");
1415
1416         /* Save it */
1417         save_bmp(filename, bmp, pal);
1418
1419         /* Free up the memory */
1420         if (bmp) destroy_bitmap(bmp);
1421
1422         /* Success message */
1423         msg_print("Screen dump saved.");
1424         msg_print(NULL);
1425 }
1426
1427
1428 /* GRX font file reader by Mark Wodrich.
1429  *
1430  * GRX FNT files consist of the header data (see struct below). If the font
1431  * is proportional, followed by a table of widths per character (unsigned
1432  * shorts). Then, the data for each character follows. 1 bit/pixel is used,
1433  * with each line of the character stored in contiguous bytes. High bit of
1434  * first byte is leftmost pixel of line.
1435  *
1436  * Note : FNT files can have a variable number of characters, so we must
1437  *        check that the chars 32..127 exist.
1438  */
1439
1440 #define FONTMAGIC       0x19590214L
1441
1442
1443 /* .FNT file header */
1444 typedef struct
1445 {
1446         unsigned long  magic;
1447         unsigned long  bmpsize;
1448         unsigned short width;
1449         unsigned short height;
1450         unsigned short minchar;
1451         unsigned short maxchar;
1452         unsigned short isfixed;
1453         unsigned short reserved;
1454         unsigned short baseline;
1455         unsigned short undwidth;
1456         char           fname[16];
1457         char           family[16];
1458 } FNTfile_header;
1459
1460
1461 #define GRX_TMP_SIZE    4096
1462
1463
1464
1465 /* converts images from bit to byte format */
1466 static void convert_grx_bitmap(int width, int height, unsigned char *src, unsigned char *dest)
1467 {
1468         unsigned short x, y, bytes_per_line;
1469         unsigned char bitpos, bitset;
1470
1471         bytes_per_line = (width + 7) >> 3;
1472
1473         for (y = 0; y < height; y++)
1474         {
1475                 for (x = 0; x < width; x++)
1476                 {
1477                         bitpos = 7-(x&7);
1478                         bitset = !!(src[(bytes_per_line * y) + (x >> 3)] & (1 << bitpos));
1479                         dest[y * width + x] = bitset;
1480                 }
1481         }
1482 }
1483
1484
1485
1486 /* reads GRX format images from disk */
1487 static unsigned char **load_grx_bmps(PACKFILE *f, FNTfile_header *hdr, int numchar, unsigned short *wtable)
1488 {
1489         int t, width, bmp_size;
1490         unsigned char *temp;
1491         unsigned char **bmp;
1492
1493         /* alloc array of bitmap pointers */
1494         bmp = malloc(sizeof(unsigned char *) * numchar);
1495
1496         /* assume it's fixed width for now */
1497         width = hdr->width;
1498
1499         /* temporary working area to store FNT bitmap */
1500         temp = malloc(GRX_TMP_SIZE);
1501
1502         for (t = 0; t < numchar; t++)
1503         {
1504                 /* if prop. get character width */
1505                 if (!hdr->isfixed)
1506                         width = wtable[t];
1507
1508                 /* work out how many bytes to read */
1509                 bmp_size = ((width + 7) >> 3) * hdr->height;
1510
1511                 /* oops, out of space! */
1512                 if (bmp_size > GRX_TMP_SIZE)
1513                 {
1514                         free(temp);
1515                         for (t--; t >= 0; t--)
1516                         free(bmp[t]);
1517                         free(bmp);
1518                         return NULL;
1519                 }
1520
1521                 /* alloc space for converted bitmap */
1522                 bmp[t] = malloc(width * hdr->height);
1523
1524                 /* read data */
1525                 pack_fread(temp, bmp_size, f);
1526
1527                 /* convert to 1 byte/pixel */
1528                 convert_grx_bitmap(width, hdr->height, temp, bmp[t]);
1529         }
1530
1531         free(temp);
1532         return bmp;
1533 }
1534
1535
1536
1537 /* main import routine for the GRX font format */
1538 static FONT *import_grx_font(char *fname)
1539 {
1540         PACKFILE *f;
1541         FNTfile_header hdr;              /* GRX font header */
1542         int numchar;                     /* number of characters in the font */
1543         unsigned short *wtable = NULL;   /* table of widths for each character */
1544         unsigned char **bmp;             /* array of font bitmaps */
1545         FONT *font = NULL;               /* the Allegro font */
1546         FONT_PROP *font_prop;
1547         int c, c2, start, width;
1548
1549         f = pack_fopen(fname, F_READ);
1550         if (!f)
1551                 return NULL;
1552
1553         pack_fread(&hdr, sizeof(hdr), f);      /* read the header structure */
1554
1555         if (hdr.magic != FONTMAGIC)             /* check magic number */
1556         {
1557                 pack_fclose(f);
1558                 return NULL;
1559         }
1560
1561         numchar = hdr.maxchar - hdr.minchar + 1;
1562
1563         if (!hdr.isfixed)                    /* proportional font */
1564         {
1565                 wtable = malloc(sizeof(unsigned short) * numchar);
1566                 pack_fread(wtable, sizeof(unsigned short) * numchar, f);
1567         }
1568
1569         bmp = load_grx_bmps(f, &hdr, numchar, wtable);
1570         if (!bmp)
1571                 goto get_out;
1572
1573         if (pack_ferror(f))
1574                 goto get_out;
1575
1576         font = malloc(sizeof(FONT));
1577         font->height = -1;
1578         font->dat.dat_prop = font_prop = malloc(sizeof(FONT_PROP));
1579         font_prop->render = NULL;
1580
1581         start = 32 - hdr.minchar;
1582         width = hdr.width;
1583
1584         for (c = 0; c  <FONT_SIZE; c++)
1585         {
1586                 c2 = c+start;
1587
1588                 if ((c2 >= 0) && (c2 < numchar))
1589                 {
1590                         if (!hdr.isfixed)
1591                                 width = wtable[c2];
1592
1593                         font_prop->dat[c] = create_bitmap_ex(8, width, hdr.height);
1594                         memcpy(font_prop->dat[c]->dat, bmp[c2], width * hdr.height);
1595                 }
1596                 else
1597                 {
1598                         font_prop->dat[c] = create_bitmap_ex(8, 8, hdr.height);
1599                         clear(font_prop->dat[c]);
1600                 }
1601         }
1602
1603         get_out:
1604
1605         pack_fclose(f);
1606
1607         if (wtable)
1608         free(wtable);
1609
1610         if (bmp)
1611         {
1612                 for (c = 0; c < numchar; c++)
1613                         free(bmp[c]);
1614
1615                 free(bmp);
1616         }
1617
1618         return font;
1619 }
1620
1621
1622 /*
1623  * Initialize the terminal windows
1624  */
1625 static bool init_windows(void)
1626 {
1627         int i, num_windows;
1628
1629         term_data *td;
1630
1631         char section[80];
1632
1633         char filename[1024];
1634
1635         char buf[128];
1636
1637         /* Section name */
1638         sprintf(section, "Mode-%d", resolution);
1639
1640         /* Get number of windows */
1641         num_windows = get_config_int(section, "num_windows", 1);
1642
1643         /* Paranoia */
1644         if (num_windows > 8) num_windows = 8;
1645
1646         /* Init the terms */
1647         for (i = 0; i < num_windows; i++)
1648         {
1649                 td = &data[i];
1650                 WIPE(td, term_data);
1651
1652                 /* Section name */
1653                 sprintf(section, "Term-%d-%d", resolution, i);
1654
1655                 /* Term number */
1656                 td->number = i;
1657
1658                 /* Coordinates of left top corner */
1659                 td->x = get_config_int(section, "x", 0);
1660                 td->y = get_config_int(section, "y", 0);
1661
1662                 /* Rows and cols of term */
1663                 td->rows = get_config_int(section, "rows", 24);
1664                 td->cols = get_config_int(section, "cols", 80);
1665
1666                 /* Tile size */
1667                 td->tile_wid = get_config_int(section, "tile_wid", 8);
1668                 td->tile_hgt = get_config_int(section, "tile_hgt", 13);
1669
1670                 /* Font size */
1671                 td->font_wid = get_config_int(section, "tile_wid", 8);
1672                 td->font_hgt = get_config_int(section, "tile_hgt", 13);
1673
1674                 /* Get font filename */
1675                 strcpy(buf, get_config_string(section, "font_file", "xm8x13.fnt"));
1676
1677                 /* Build the name of the font file */
1678                 path_build(filename, 1024, xtra_font_dir, buf);
1679
1680                 /* Load a "*.fnt" file */
1681                 if (suffix(filename, ".fnt"))
1682                 {
1683                         /* Load the font file */
1684                         if (!(td->font = import_grx_font(filename)))
1685                         {
1686                                 quit_fmt("Error reading font file '%s'", filename);
1687                         }
1688                 }
1689
1690                 /* Load a "*.dat" file */
1691                 else if (suffix(filename, ".dat"))
1692                 {
1693                         DATAFILE *fontdata;
1694
1695                         /* Load the font file */
1696                         if (!(fontdata = load_datafile(filename)))
1697                         {
1698                                 quit_fmt("Error reading font file '%s'", filename);
1699                         }
1700
1701                         /* Save the font data */
1702                         td->font = fontdata[1].dat;
1703
1704                         /* Unload the font file */
1705                         unload_datafile_object(fontdata);
1706                 }
1707
1708                 /* Oops */
1709                 else
1710                 {
1711                         quit_fmt("Unknown suffix in font file '%s'", filename);
1712                 }
1713
1714                 /* Link the term */
1715                 term_data_link(td);
1716                 angband_term[i] = &td->t;
1717         }
1718
1719         /* Success */
1720         return 0;
1721 }
1722
1723
1724 #ifdef USE_BACKGROUND
1725
1726 /*
1727  * Initialize the window backgrounds
1728  */
1729 static void init_background(void)
1730 {
1731         int i;
1732
1733         char filename[1024];
1734
1735         char buf[128];
1736
1737         PALLETE background_pallete;
1738
1739         /* Get the backgrounds */
1740         for (i = 0; i < 16; i++)
1741         {
1742                 /* Get background filename */
1743                 strcpy(buf, get_config_string("Background", format("Background-%d", i), ""));
1744
1745                 /* Build the filename for the background-bitmap */
1746                 path_build(filename, 1024, xtra_graf_dir, buf);
1747
1748                 /* Try to open the bitmap file */
1749                 background[i] = load_bitmap(filename, background_pallete);
1750         }
1751
1752 #ifndef USE_SPECIAL_BACKGROUND
1753         /*
1754          * Set the palette for the background
1755          */
1756         if (background[0])
1757         {
1758                 set_palette_range(background_pallete, 0, COLOR_OFFSET - 1, 0);
1759         }
1760 #endif /* USE_SPECIAL_BACKGROUND */
1761 }
1762
1763 #endif /* USE_BACKGROUND */
1764
1765
1766 #ifdef USE_GRAPHICS
1767
1768 /*
1769  * Initialize graphics
1770  */
1771 static bool init_graphics(void)
1772 {
1773         char filename[1024];
1774         char section[80];
1775         char name_tiles[128];
1776
1777         /* Large bitmap for the tiles */
1778         BITMAP *tiles = NULL;
1779         PALLETE tiles_pallete;
1780
1781         /* Size of each bitmap tile */
1782         int bitmap_wid;
1783         int bitmap_hgt;
1784
1785         int num_windows;
1786
1787         if (!graphics_initialized)
1788         {
1789                 /* Section name */
1790                 sprintf(section, "Mode-%d", resolution);
1791
1792                 /* Get bitmap tile size */
1793                 bitmap_wid = get_config_int(section, "bitmap_wid", 8);
1794                 bitmap_hgt = get_config_int(section, "bitmap_hgt", 8);
1795
1796                 /* Get bitmap filename */
1797                 strcpy(name_tiles, get_config_string(section, "bitmap_file", "8x8.bmp"));
1798
1799                 /* Get number of windows */
1800                 num_windows = get_config_int(section, "num_windows", 1);
1801
1802                 /* Build the name of the bitmap file */
1803                 path_build(filename, 1024, xtra_graf_dir, name_tiles);
1804
1805                 /* Open the bitmap file */
1806                 if ((tiles = load_bitmap(filename, tiles_pallete)) != NULL)
1807                 {
1808                         int i;
1809
1810                         /*
1811                          * Set the graphics mode to "new" if Adam Bolt's
1812                          * new 16x16 tiles are used.
1813                          */
1814                         ANGBAND_GRAF = get_config_string(section, "graf-mode", "old");
1815
1816                         /* Select the bitmap pallete */
1817                         set_palette_range(tiles_pallete, 0, COLOR_OFFSET - 1, 0);
1818
1819                         /* Prepare the graphics */
1820                         for (i = 0; i < num_windows; i++)
1821                         {
1822                                 term_data *td;
1823
1824                                 int col, row;
1825                                 int cols, rows;
1826                                 int width, height;
1827                                 int src_x, src_y;
1828                                 int tgt_x, tgt_y;
1829
1830                                 td = &data[i];
1831
1832                                 cols = tiles->w / bitmap_wid;
1833                                 rows = tiles->h / bitmap_hgt;
1834
1835                                 width = td->tile_wid * cols;
1836                                 height = td->tile_hgt * rows;
1837
1838                                 /* Initialize the tile graphics */
1839                                 td->tiles = create_bitmap(width, height);
1840
1841                                 for (row = 0; row < rows; ++row)
1842                                 {
1843                                         src_y = row * bitmap_hgt;
1844                                         tgt_y = row * td->tile_hgt;
1845
1846                                         for (col = 0; col < cols; ++col)
1847                                         {
1848                                                 src_x = col * bitmap_wid;
1849                                                 tgt_x = col * td->tile_wid;
1850
1851                                                 stretch_blit(tiles, td->tiles,
1852                                                         src_x, src_y,
1853                                                         bitmap_wid, bitmap_hgt,
1854                                                         tgt_x, tgt_y,
1855                                                         td->tile_wid, td->tile_hgt);
1856                                         }
1857                                 }
1858                         }
1859
1860                         /* Free the old tiles bitmap */
1861                         if (tiles) destroy_bitmap(tiles);
1862
1863                         graphics_initialized = TRUE;
1864
1865                         /* Success */
1866                         return (TRUE);
1867                 }
1868
1869                 /* Failure */
1870                 return (FALSE);
1871         }
1872
1873         /* Success */
1874         return (TRUE);
1875 }
1876
1877 #endif /* USE_GRAPHICS */
1878
1879 #ifdef USE_SOUND
1880
1881 /*
1882  * Initialize sound
1883  * We try to get a list of the available sound-files from "lib/xtra/sound/sound.cfg"
1884  * and then preload the samples. Every Angband-sound-event can have several samples
1885  * assigned. Angband will randomly select which is played. This makes it easy to
1886  * create "sound-packs", just copy wav-files into the "lib/xtra/sound/" folder and
1887  * add the filenames to "sound.cfg" in the same folder.
1888  */
1889 static bool init_sound(void)
1890 {
1891         int i, j, done;
1892
1893         char section[128];
1894         char filename[1024];
1895         char **argv;
1896
1897         struct ffblk f;
1898
1899         if (sound_initialized) return (TRUE);
1900
1901         reserve_voices(16, -1);
1902
1903         /* Initialize Allegro sound */
1904         if (!install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL))
1905         {
1906 #ifdef USE_MOD_FILES
1907                 /*
1908                  * Try to enable support for MOD-, and S3M-files
1909                  * The parameter for install_mod() is the number
1910                  * of channels reserved for the MOD/S3M-file.
1911                  */
1912                 if (install_mod(8) > 0) mod_file_initialized = TRUE;
1913 #endif /* USE_MOD_FILES */
1914
1915                 /* Access the new sample */
1916                 path_build(filename, 1024, xtra_sound_dir, "sound.cfg");
1917
1918                 /* Read config info from "lib/xtra/sound/sound.cfg" */
1919                 override_config_file(filename);
1920
1921                 /* Sound section */
1922                 strcpy(section, "Sound");
1923
1924                 /* Prepare the sounds */
1925                 for (i = 1; i < SOUND_MAX; i++)
1926                 {
1927                         /* Get the sample names */
1928                         argv = get_config_argv(section, angband_sound_name[i], &sample_count[i]);
1929
1930                         /* Limit the number of samples */
1931                         if (sample_count[i] > SAMPLE_MAX) sample_count[i] = SAMPLE_MAX;
1932
1933                         for (j = 0; j < sample_count[i]; j++)
1934                         {
1935                                 /* Access the new sample */
1936                                 path_build(filename, 1024, xtra_sound_dir, argv[j]);
1937
1938                                 /* Load the sample */
1939                                 samples[i][j] = load_sample(filename);
1940                         }
1941                 }
1942
1943                 /*
1944                  * Get a list of music files
1945                  */
1946 #ifdef USE_MOD_FILES
1947                 if (mod_file_initialized)
1948                 {
1949                         done = findfirst(format("%s/*.*", xtra_music_dir), &f, FA_ARCH|FA_RDONLY);
1950                 }
1951                 else
1952 #endif /* USE_MOD_FILES */
1953                 done = findfirst(format("%s/*.mid", xtra_music_dir), &f, FA_ARCH|FA_RDONLY);
1954
1955
1956                 while (!done && (song_number <= MAX_SONGS))
1957                 {
1958                         /* Add music files */
1959                         {
1960                                 strcpy(music_files[song_number], f.ff_name);
1961                                 song_number++;
1962                         }
1963
1964                         done = findnext(&f);
1965                 }
1966
1967                 /* Use "angdos.cfg" */
1968                 override_config_file("angdos.cfg");
1969
1970                 /* Sound section */
1971                 strcpy(section, "Sound");
1972
1973                 /* Get the volume setting */
1974                 digi_volume = get_config_int(section, "digi_volume", 255);
1975                 midi_volume = get_config_int(section, "midi_volume", 255);
1976
1977                 /* Set the volume */
1978                 set_volume(digi_volume, midi_volume);
1979
1980                 /* Success */
1981                 return (TRUE);
1982         }
1983
1984         /* Init failed */
1985         return (FALSE);
1986 }
1987
1988
1989 /*
1990  * Make a sound
1991  */
1992 static errr Term_xtra_dos_sound(int v)
1993 {
1994         int n;
1995
1996         /* Sound disabled */
1997         if (!use_sound) return (1);
1998
1999         /* Illegal sound */
2000         if ((v < 0) || (v >= SOUND_MAX)) return (1);
2001
2002         /* Get a random sample from the available ones */
2003         n = randint0(sample_count[v]);
2004
2005         /* Play the sound, catch errors */
2006         if (samples[v][n])
2007         {
2008                 return (play_sample(samples[v][n], 255, 128, 1000, 0) == 0);
2009         }
2010
2011         /* Oops */
2012         return (1);
2013 }
2014
2015
2016 /*
2017  * Play a song-file
2018  */
2019 static void play_song(void)
2020 {
2021         char filename[256];
2022
2023         /* Clear the old song */
2024         if (midi_song) destroy_midi(midi_song);
2025         midi_song = NULL;
2026
2027 #ifdef USE_MOD_FILES
2028         if (mod_file_initialized)
2029         {
2030                 stop_mod();
2031                 destroy_mod(mod_song);
2032         }
2033 #endif /* USE_MOD_FILES */
2034
2035         /* Access the new song */
2036         path_build(filename, 1024, xtra_music_dir, music_files[current_song - 1]);
2037
2038         /* Load and play the new song */
2039         midi_song = load_midi(filename);
2040
2041         if (midi_song)
2042         {
2043                 play_midi(midi_song, 0);
2044         }
2045 #ifdef USE_MOD_FILES
2046         else if (mod_file_initialized)
2047         {
2048                 mod_song = load_mod(filename);
2049
2050                 if (mod_song) play_mod(mod_song, FALSE);
2051         }
2052 #endif /* USE_MOD_FILES */
2053 }
2054
2055 #endif /* USE_SOUND */
2056
2057
2058 /*
2059  * Attempt to initialize this file
2060  *
2061  * Hack -- we assume that "blank space" should be "white space"
2062  * (and not "black space" which might make more sense).
2063  *
2064  * Note the use of "((x << 2) | (x >> 4))" to "expand" a 6 bit value
2065  * into an 8 bit value, without losing much precision, by using the 2
2066  * most significant bits as the least significant bits in the new value.
2067  *
2068  * We should attempt to "share" bitmaps (and fonts) between windows
2069  * with the same "tile" size.  XXX XXX XXX
2070  */
2071 errr init_dos(void)
2072 {
2073         term_data *td;
2074
2075         char section[80];
2076
2077         int screen_wid;
2078         int screen_hgt;
2079
2080         /* Initialize the Allegro library (never fails) */
2081         (void)allegro_init();
2082
2083         /* Install timer support for music and sound */
2084         install_timer();
2085
2086         /* Read config info from filename */
2087         set_config_file("angdos.cfg");
2088
2089         /* Main section */
2090         strcpy(section, "Angband");
2091
2092         /* Get screen size */
2093         resolution = get_config_int(section, "Resolution", 1);
2094
2095         /* Section name */
2096         sprintf(section, "Mode-%d", resolution);
2097
2098         /* Get the screen dimensions */
2099         screen_wid = get_config_int(section, "screen_wid", 640);
2100         screen_hgt = get_config_int(section, "screen_hgt", 480);
2101
2102         /* Set the color depth */
2103         set_color_depth(8);
2104
2105         /* Auto-detect, and instantiate, the appropriate graphics mode */
2106         if ((set_gfx_mode(GFX_AUTODETECT, screen_wid, screen_hgt, 0, 0)) < 0)
2107         {
2108                 /*
2109                  * Requested graphics mode is not available
2110                  * We retry with the basic 640x480 mode
2111                  */
2112                 resolution = 1;
2113
2114                 if ((set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0)) < 0)
2115                 {
2116                         char error_text[1024];
2117
2118                         /* Save the Allegro error description */
2119                         strcpy(error_text, allegro_error);
2120
2121                         /* Shut down Allegro */
2122                         allegro_exit();
2123
2124                         /* Print the error description */
2125                         plog_fmt("Error selecting screen mode: %s", error_text);
2126
2127                         /* Failure */
2128                         return (-1);
2129                 }
2130         }
2131
2132         /* Hook in "z-util.c" hook */
2133         quit_aux = dos_quit_hook;
2134
2135         /* Build the "graf" path */
2136         path_build(xtra_graf_dir, 1024, ANGBAND_DIR_XTRA, "graf");
2137
2138         /* Build the "font" path */
2139         path_build(xtra_font_dir, 1024, ANGBAND_DIR_XTRA, "font");
2140
2141         /* Build the "sound" path */
2142         path_build(xtra_sound_dir, 1024, ANGBAND_DIR_XTRA, "sound");
2143
2144         /* Build the "music" path */
2145         path_build(xtra_music_dir, 1024, ANGBAND_DIR_XTRA, "music");
2146
2147         /* Initialize the windows */
2148         init_windows();
2149
2150 #ifdef USE_SOUND
2151
2152         /* Look for the sound preferences in "angdos.cfg" */
2153         if (!arg_sound)
2154         {
2155                 arg_sound = get_config_int("Angband", "Sound", TRUE);
2156         }
2157
2158 #endif /* USE_SOUND */
2159
2160 #ifdef USE_GRAPHICS
2161
2162         /* Look for the graphic preferences in "angdos.cfg" */
2163         if (!arg_graphics)
2164         {
2165                 arg_graphics = get_config_int("Angband", "Graphics", GRAPHICS_ORIGINAL);
2166         }
2167
2168 #endif /* USE_GRAPHICS */
2169
2170         /* Initialize the "complex" RNG for the midi-shuffle function */
2171         Rand_quick = FALSE;
2172         Rand_state_init(time(NULL));
2173
2174         /* Set the Angband colors/graphics/sound mode */
2175         Term_xtra_dos_react();
2176
2177 #ifdef USE_BACKGROUND
2178
2179         /* Initialize the background graphics */
2180         init_background();
2181
2182 #endif /* USE_BACKGROUND */
2183
2184         /* Clear the screen */
2185         clear_to_color(screen, COLOR_OFFSET + TERM_DARK);
2186
2187         /* Main screen */
2188         td = &data[0];
2189
2190         /* Build a cursor bitmap */
2191         cursor = create_bitmap(td->tile_wid, td->tile_hgt);
2192
2193         /* Erase the cursor sprite */
2194         clear(cursor);
2195
2196         /* Draw the cursor sprite (yellow rectangle) */
2197         rect(cursor, 0, 0, td->tile_wid - 1, td->tile_hgt - 1,
2198              COLOR_OFFSET + TERM_YELLOW);
2199
2200         /* Activate the main term */
2201         Term_activate(angband_term[0]);
2202
2203         /* Place the cursor */
2204         Term_curs_dos(0, 0);
2205
2206 #ifdef USE_BACKGROUND
2207
2208         /* Use transparent text */
2209         text_mode(-1);
2210
2211 #endif /* USE_BACKGROUND */
2212
2213         /* Success */
2214         return 0;
2215 }
2216
2217 #endif /* USE_DOS */
2218