1 /*
2 * File: main-ros.c
3 *
4 * Abstract: Support for RISC OS versions of Angband, including support
5 * for multitasking and dynamic areas.
6 *
7 * Authors: Musus Umbra, Andrew Sidwell, Ben Harrison, and others.
8 *
9 * Licences: Angband licence.
10 */
11
12 #ifdef __riscos
13
14 #include "angband.h"
15
16 /*
17 * Purpose: Support for RISC OS Angband 2.9.x onwards (and variants)
18 *
19 * NB: This code is still under continuous development - if you want to use
20 * it for your own compilation/variant, please contact me so that I can
21 * keep you up to date and give you support :)
22 *
23 * Prerequisites to compiling:
24 *
25 * DeskLib 2.30 or later (earlier versions may be OK though)
26 *
27 * An ANSI C compiler (tested with Acorn's C/C++ and GCC, but should be OK
28 * with any decent compiler)
29 *
30 * My binary distribution (for the templates and other bits)
31 *
32 * Note:
33 * The following symbols are *required* and *must* be defined properly.
34 */
35
36 /*
37 * VARIANT & VERSION
38 * These two get variant and version data from Angband itself; older
39 * variants may not have these defined and will have to be altered.
40 */
41 #define VARIANT VERSION_NAME
42 #define VERSION VERSION_STRING
43
44 /*
45 * PORTVERSION
46 * This is the port version; it appears in the infobox.
47 */
48 #define PORTVERSION "1.29-dev (2003-07-27)"
49
50 /*
51 * RISCOS_VARIANT
52 * This must match the entry in the !Variant Obey file, and it must only
53 * contain characters that are valid as part of a RISC OS path variable.
54 * [eg. "Yin-Yangband" is not okay, "EyAngband" is.]
55 */
56 #define RISCOS_VARIANT "Zangband"
57
58 /*
59 * AUTHORS
60 * For the info box. [eg. "Ben Harrison"]
61 */
62 #define AUTHORS "Zangband dev team"
63
64 /*
65 * PORTERS
66 * For the info box. [eg. "Musus Umbra"]
67 */
68 #define PORTERS "A. Sidwell"
69
70 /*
71 * ICONNAME
72 * Iconbar icon sprite name eg. "!angband". Note that this must be a valid
73 * sprite name; it may need modifying for long variant names.
74 */
75 #define ICONNAME "!"RISCOS_VARIANT
76
77 /*
78 * PDEADCHK
79 * This should expand to an expression that is true if the player is dead.
80 * [eg. (p_ptr->is_dead) for Angband or (!alive || dead) for some Zangbands]
81 */
82
83 #define PDEADCHK (p_ptr->state.is_dead)
84
85 /*
86 * The following symbols control the (optional) file-cache:
87 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88 * NB: Variants that don't repeatedly read any files whilst running
89 * (eg. vanilla, sang, etc) should NOT define USE_FILECACHE, etc. as
90 * it causes a non-negligable amount of code to be compiled in.
91 *
92 * NB: The file-cache functions require that some code in files.c is modified
93 * to use the cached_* functions. This should be utterly trivial.
94 *
95 * NB: The returned handle from cached_fopen() is almost certainly *NOT*
96 * a |FILE*| (although it may be if the cache cannot accomodate the file).
97 *
98 * Therefore, you *MUST* ensure that any file opened with cached_fopen()
99 * is only ever accessed via cached_fgets() and cached_fclose().
100 *
101 * Failure to do so will result in, ahem, unpleasantness. Extreme
102 * unpleasantness. "Him fall down, go boom."
103 *
104 * This /may/ change in the near future (ie. to apply caching in a
105 * transparent manner), so do keep a backup of files.c (and any other files
106 * you modify). You always keep backups anyway, don't you? Don't you?!
107 */
108
109 /*
110 * USE_FILECACHE
111 * if defined then some caching functions will be compiled for use by the
112 * various get_rnd_line(), etc. in files.c. This could be used in a
113 * variety of places that read data repeatedly, but it's up to you to
114 * implement it then.
115 */
116
117 /* #define USE_FILECACHE */
118
119 /*
120 * SMART_FILECACHE
121 * This causes lines beginning with '#' (and blank lines) to be discarded
122 * when caching files. This should help Zangband 2.2.5+ but could cause
123 * trouble for other variants. If defined, then smart file caching will be
124 * on by default.
125 */
126
127 /* #define SMART_FILECACHE */
128
129 /*
130 * ABBR_FILECACHE
131 * ABBR_FILECACHE causes data read into file-cache to be compressed (using a
132 * simple set of abbreviations) by default. This can be overridden using a
133 * command line option. If this symbol is not defined then no compression
134 * code will be compiled and the user option will be ignored/unavailable.
135 */
136
137 /* #define ABBR_FILECACHE */
138
139 /*
140 * Note:
141 * The following symbols control debugging information.
142 */
143
144 /*
145 * FE_DEBUG_INFO
146 * If defined, some functions will be compiled to display some info. on the
147 * state of the front-end (accessible) from the '!' user menu.
148 *
149 * NB: For actual releases you should NOT define this symbol since it causes
150 * a non-negligable amount of code/data to be sucked in.
151 */
152 /* #define FE_DEBUG_INFO */
153
154 /*
155 * USE_DA
156 * If defined, it enables the use of dynamic areas (these are still only
157 * used when the !Variant file allows it). It is likely that this option
158 * will eventually be removed altogether as there is no major advantege
159 * to using DAs over just using the Wimpslot.
160 */
161 #define USE_DA
162
163
164 /* Constants, etc. ---------------------------------------------------------*/
165
166 /* Deal with any weird file-caching symbols */
167 #ifndef USE_FILECACHE
168 # undef ABBR_FILECACHE
169 # undef SMART_FILECACHE
170 #endif
171
172 /* Maximum terminals */
173 #define MAX_TERM_DATA 8
174
175 /* Menu entry numbers */
176 #define IBAR_MENU_INFO 0
177 #define IBAR_MENU_SAVE 1
178 #define IBAR_MENU_FULLSCREEN 2
179 #define IBAR_MENU_GAMMA 3
180 #define IBAR_MENU_SOUND 4
181 #define IBAR_MENU_WINDOWS 5
182 #define IBAR_MENU_SAVECHOICES 6
183 #define IBAR_MENU_QUIT 7
184
185 #define TERM_MENU_INFO 0
186 #define TERM_MENU_SAVE 1
187 #define TERM_MENU_FONT 2
188 #define TERM_MENU_WINDOWS 3
189
190 /* Icon numbers */
191 #define SND_VOL_SLIDER 0
192 #define SND_VOL_DOWN 1
193 #define SND_VOL_UP 2
194 #define SND_ENABLE 3
195
196 #define GAMMA_ICN 0
197 #define GAMMA_DOWN 1
198 #define GAMMA_UP 2
199
200 #define SAVE_ICON 2
201 #define SAVE_PATH 1
202 #define SAVE_OK 0
203 #define SAVE_CANCEL 3
204
205 /* Position and size of the colours strip in the gamma window */
206 #define GC_XOFF 20
207 #define GC_YOFF -14
208 #define GC_WIDTH 512
209 #define GC_HEIGHT 72
210
211 /* Maximum and minimum allowed volume levels */
212 #define SOUND_VOL_MIN 16
213 #define SOUND_VOL_MAX 176
214
215 /*--------------------------------------------------------------------------*/
216
217
218 #undef rename
219 #undef remove
220
221 #include "Desklib:Event.h"
222 #include "Desklib:EventMsg.h"
223 #include "Desklib:Template.h"
224 #include "Desklib:Window.h"
225 #include "Desklib:Handler.h"
226 #include "Desklib:Screen.h"
227 #include "Desklib:Menu.h"
228 #include "Desklib:Msgs.h"
229 #include "Desklib:Icon.h"
230 #include "Desklib:Resource.h"
231 #include "Desklib:SWI.h"
232 #include "Desklib:Time.h"
233 #include "Desklib:Sound.h"
234 #include "Desklib:KeyCodes.h"
235 #include "Desklib:Kbd.h"
236 #include "Desklib:GFX.h"
237 #include "Desklib:ColourTran.h"
238 #include "Desklib:Error.h"
239 #include "Desklib:Coord.h"
240 #include "Desklib:Slider.h"
241 #include "Desklib:Hourglass.h"
242 #include "Desklib:Save.h"
243 #include "Desklib:Sprite.h"
244 #include "Desklib:KernelSWIs.h"
245
246 #include <stdlib.h>
247 #include <stdio.h>
248 #include <string.h>
249 #include <ctype.h>
250 #include <signal.h>
251 #include <stdarg.h>
252 #include <time.h>
253 #include <math.h>
254
255 /*--------------------------------------------------------------------------*/
256
257 /*
258 | We use the hourglass around calls to Wimp_Poll in an attempt to stop
259 | users thinking that the game has 'hung'.
260 | Kamband/Zangband and the Borg in particular can have quite long delays at
261 | times.
262 */
263 #define Start_Hourglass \
264 { if ( use_glass && !glass_on ) { glass_on=1; Hourglass_Start(50); } }
265 #define Stop_Hourglass \
266 { if ( glass_on ) { glass_on=0; Hourglass_Off(); } }
267
268
269 /*--------------------------------------------------------------------------*/
270 /* Types */
271 /*--------------------------------------------------------------------------*/
272
273 /*
274 | A ZapRedraw block
275 */
276 typedef struct
277 {
278 union
279 {
280 unsigned int value;
281 struct
282 {
283 unsigned int vdu:1;
284 unsigned int double_height:1;
285 unsigned int extension:1;
286 unsigned int padding:29;
287 }
288 bits;
289 }
290 r_flags;
291
292 int r_minx; /* min x of redraw in pixels from LHS, incl */
293 int r_miny; /* min y of redraw in pixels from top, incl */
294 int r_maxx; /* max x of redraw in pixels from LHS, excl */
295 int r_maxy; /* max y of redraw in pixels from top, excl */
296
297 void *r_screen; /* DSA: address of screen to write to (0=>read) */
298 int r_bpl; /* DSA: bytes per raster line */
299
300 int r_bpp; /* log base 2 of bits per pixel */
301 int r_charw; /* width of a character in pixels */
302 int r_charh; /* height of a character in pixels */
303 void *r_caddr; /* DSA: ->character cache | VDU: ->font name */
304 int r_cbpl; /* DSA: #bytes/character line | VDU: x OS offset */
305 int r_cbpc; /* DSA: #bytes/character | VDU: y OS offset */
306
307 int r_linesp; /* line spacing (pixels) */
308
309 void *r_data; /* -> text to display */
310 int r_scrollx; /* see Redraw dox */
311 int r_scrolly; /* see Redraw dox */
312
313 void *r_palette; /* -> palette lookup table */
314 int r_for; /* foreground colour at start of line */
315 int r_bac; /* background colour at start of line */
316
317 void *r_workarea; /* -> word aligned workspace */
318
319 int r_magx; /* log2 x OS coords per pixel */
320 int r_magy; /* log2 y OS coords per pixel */
321
322 int r_xsize; /* width of screen in pixels */
323 int r_ysize; /* height of screen in pixels */
324
325 int r_mode; /* current screen mode */
326 }
327 ZapRedrawBlock;
328
329
330 /*
331 | We cache font data using an array of 'font handles' (since there is a
332 | known maximum no. of fonts required).
333 | This is what a font 'handle' looks like:
334 */
335 typedef struct
336 {
337 char *name; /* font name */
338 int usage; /* usage count */
339 int w, h; /* width, height */
340 int f, l; /* first and last character defined */
341 void *bpp_1; /* source bitmap */
342 void *bpp_n; /* bitmap for the current screen mode */
343 }
344 ZapFont;
345
346 /*
347 | A struct to hold all the data relevant to a term window
348 */
349 typedef struct
350 {
351 term t; /* The Term itself */
352 window_handle w; /* Window handle */
353 ZapFont *font; /* Font */
354 wimp_box changed_box; /* Area out of date */
355 struct
356 {
357 wimp_point pos; /* Cursor position */
358 BOOL visible; /* visibility flag */
359 }
360 cursor;
361 char name[12]; /* Name to give menus opened from the term */
362 int def_open; /* Open by default? */
363 wimp_box def_pos; /* default position */
364 wimp_point def_scroll; /* default scroll offset */
365 int unopened; /* Has this window not been opened yet? */
366 }
367 term_data;
368
369
370
371 /*--------------------------------------------------------------------------*/
372 /* ZapRedraw SWI numbers */
373 /*--------------------------------------------------------------------------*/
374
375 #define SWI_ZapRedraw_ 0x48480
376 #define SWI_ZapRedraw_RedrawArea (SWI_ZapRedraw_ + 0x00)
377 #define SWI_ZapRedraw_GetPaletteEntry (SWI_ZapRedraw_ + 0x01)
378 #define SWI_ZapRedraw_RedrawRaster (SWI_ZapRedraw_ + 0x02)
379 #define SWI_ZapRedraw_ConvertBitmap (SWI_ZapRedraw_ + 0x03)
380 #define SWI_ZapRedraw_PrepareDataLine (SWI_ZapRedraw_ + 0x04)
381 #define SWI_ZapRedraw_AddCursor (SWI_ZapRedraw_ + 0x05)
382 #define SWI_ZapRedraw_FindCharacter (SWI_ZapRedraw_ + 0x06)
383 #define SWI_ZapRedraw_MoveBytes (SWI_ZapRedraw_ + 0x07)
384 #define SWI_ZapRedraw_CachedCharSize (SWI_ZapRedraw_ + 0x08)
385 #define SWI_ZapRedraw_ConvBitmapChar (SWI_ZapRedraw_ + 0x09)
386 #define SWI_ZapRedraw_CreatePalette (SWI_ZapRedraw_ + 0x0a)
387 #define SWI_ZapRedraw_InsertChar (SWI_ZapRedraw_ + 0x0b)
388 #define SWI_ZapRedraw_ReadSystemChars (SWI_ZapRedraw_ + 0x0c)
389 #define SWI_ZapRedraw_ReverseBitmaps (SWI_ZapRedraw_ + 0x0d)
390 #define SWI_ZapRedraw_ReadVduVars (SWI_ZapRedraw_ + 0x0e)
391 #define SWI_ZapRedraw_GetRectangle (SWI_ZapRedraw_ + 0x0f)
392 #define SWI_ZapRedraw_AddVduBitmaps (SWI_ZapRedraw_ + 0x10)
393 #define SWI_ZapRedraw_CacheFontChars (SWI_ZapRedraw_ + 0x11)
394 #define SWI_ZapRedraw_SpriteSize (SWI_ZapRedraw_ + 0x12)
395 #define SWI_ZapRedraw_RedrawWindow (SWI_ZapRedraw_ + 0x13)
396
397
398 /*
399 | Other SWI numbers that aren't defined in DeskLib's SWI.h:
400 */
401 #define SWI_OS_ScreenMode 0x65
402 #define SWI_OS_DynamicArea 0x66
403 #define SWI_ColourTrans_ReturnColourNumber 0x40744
404 #define SWI_Wimp_ReportError 0x400df
405 #define SWI_PlayIt_Volume 0x4d146
406
407
408
409 /*--------------------------------------------------------------------------*
410 | File scope variables |
411 *--------------------------------------------------------------------------*/
412 static int ftype = 0xffd; /* hack so saved games get the right type */
413 static int filehandle[16]; /* we keep track of open files with this */
414 static int openfiles = 0; /* how many files are currently open */
415
416 /*
417 | Paths we use...
418 */
419 static char resource_path[260] = ""; /* Path pointng to "!Angband.Lib." */
420 static char scrap_path[260] = ""; /* Path to create scrap files on */
421 static char choices_file[3][260] =
422 { "", "", "" }; /* Choices paths (read/write, mirror, read) */
423 static char alarm_file[2][260] =
424 { "", "" }; /* Alarm choices paths (read/write, mirror, read) */
425 /*
426 | So we can use something more meaningful later...
427 | NB: Mirror is only meaningful for Choices and we don't
428 | even reserve space for alarm_file[CHFILE_MIRROR].
429 */
430 #define CHFILE_WRITE 0
431 #define CHFILE_READ 1
432 #define CHFILE_MIRROR 2
433
434 /*
435 | Other 'globals':
436 */
437 static int initialised = 0; /* Used to determine whether to try to save */
438 static int game_in_progress = 0; /* if Quit (or core() is called), etc. */
439
440 static byte a_palette[256][4]; /* a copy of the raw Angband palette */
441 static unsigned int palette[256]; /* palette as gamma'd bbggrrxx words */
442 static unsigned int zpalette[256]; /* And our version for ZapRedraw */
443 static double gamma = 1.0; /* assume gamma of 1.0 if unspecified */
444
445 static int enable_sound = 0; /* enable sound FX */
446 static int sound_volume = 127; /* Full volume */
447 static int force_mono = 0; /* force monochrome */
448 static int start_fullscreen = 0; /* start up full screen (added in 1.18) */
449 static int hack_flush = 0; /* Should TERM_XTRA_FLUSH wait for all keys to be released? */
450 static int flush_scrap = 1; /* Should any scrapfiles (incl. filecache) be deleted at exit? */
451 static int max_file_cache_size = 64 << 10;
452 static unsigned int vfiletype;
453 static int allow_iclear_hack = 0; /* Allow the hideously evil Iclear workaround thing */
454 static int alarm_type = 0; /* is there an alarm set? */
455 static int alarm_h = 0, alarm_m = 0; /* alarm time (midnight) */
456 static char alarm_message[80] = "Time for bed!"; /* the message to give */
457 static int alarm_disp = 0; /* is the alarm being displayed? */
458 static int alarm_beep = 0; /* should be beep? */
459 static const char *alarm_types[] =
460 { "Off", "On (one-shot)", "On (repeating)", "On (one-shot)" };
461 static unsigned int alarm_lastcheck = 0;
462
463
464 /* A little macro to save some typing later: */
465 #define COLOUR_CHANGED(x) \
466 ( (angband_color_table[x][1]!=a_palette[x][1]) || \
467 (angband_color_table[x][2]!=a_palette[x][2]) || \
468 (angband_color_table[x][3]!=a_palette[x][3]) )
469
470 static int got_caret = 0; /* Do we own the caret? */
471 static int key_pressed = 0; /* 'Key has been pressed' Flag */
472 static int use_glass = 1; /* use the hourglass between WimpPolls? */
473 static int glass_on = 1; /* is the hourglass on? */
474 static int user_menu_active = FALSE; /* set to TRUE when the user menu is active */
475
476 /* Font system variables */
477 static ZapFont fonts[MAX_TERM_DATA + 1]; /* The +1 is for the system font */
478
479 /* The system font is always font 0 */
480 #define SYSTEM_FONT (&(fonts[0]))
481
482 /* Term system variables */
483 static term_data data[MAX_TERM_DATA]; /* One per term */
484
485 #ifndef FULLSCREEN_ONLY
486 static char r_data[24 * (80 * 5 + 4) + 25 * 4]; /* buffer for ZapRedraw data */
487
488 /* Wimp variables */
489 static icon_handle ibar_icon; /* Iconbar icon handle */
490 static window_handle info_box; /* handle of the info window */
491 static window_handle gamma_win; /* gamma correction window */
492 static window_handle sound_win; /* sound options window */
493 static window_handle save_box; /* The savebox */
494 static menu_ptr ibar_menu; /* Iconbar menu */
495 static menu_ptr term_menu; /* Term window menu */
496 static menu_ptr wind_menu; /* windows (sub) menu */
497 static menu_ptr font_menu; /* Font (sub)menu */
498
499 static save_saveblock *saveblk = NULL; /* For the save box */
500
501 /* List of Wimp messages we want to be given */
502 static int message_list[] =
503 {
504 message_MODECHANGE,
505 message_PALETTECHANGE,
506
507 /* For the savebox */
508 message_MENUWARN,
509 message_DATASAVEACK,
510
511 message_PREQUIT,
512 0
513 };
514
515
516 static term_data *menu_term; /* term the last menu was opened for */
517
518 #endif /* FULLSCREEN_ONLY */
519
520 static ZapRedrawBlock zrb; /* a redraw block */
521
522 /* Cursor colour */
523 #define CURSOR_COLOUR 255 /* Cursor's Angband colour */
524 #define CURSOR_RGB 0x00ffff00 /* if undefined, use bbggrrxx */
525
526 static int cursor_rgb = -1; /* colour to use for cursor */
527
528 static int fullscreen_mode = 0; /* screen mode in use */
529 static int old_screenmode = 0; /* Mode we started out in */
530 static int *fullscreen_font = 0; /* font data for fullscreen use */
531 static int *fullscreen_base = 0; /* base address of screen */
532 static int fullscreen_height; /* height of the fullscreen font */
533 static int fullscreen_topline; /* raster offset of fullscreen */
534
535 #define KEYPRESS_QUIT 0x1cc /* F12 gets back to the desktop */
536 #define TERM_TOPLINE_HR 32 /* vertical pixel offset in mode 27 */
537 #define TERM_TOPLINE_LR 16 /* vertical pixel offset in mode 12 */
538 #define TIME_LINE 26 /* Line to display the clock on */
539
540 /* text to display at the bottom left of the fullscreen display */
541 static const char *fs_quit_key_text = "Press f12 to return to the desktop";
542 static const char *alarm_cancel_text = "(Press ^Escape to cancel the alarm)";
543
544 /* Debugging flags, etc. */
545 static int log_g_malloc = 0; /* Log calls to ralloc, etc */
546 static int show_sound_alloc = 0; /* Log sound mappings, etc */
547
548 /* Activate file caching? */
549 #ifdef USE_FILECACHE
550 static int use_filecache = TRUE;
551 #else
552 static int use_filecache = FALSE;
553 #endif
554
555 /* Cripple some things to save memory */
556 static int minimise_memory = 0;
557
558 /* Forward declarations of some of the Full Screen Mode stuff */
559 static void enter_fullscreen_mode(void);
560 static void leave_fullscreen_mode(void);
561 static void set_keys(int claim);
562
563 /* Forwards declarations of the sound stuff */
564 static void initialise_sound(void);
565 static void play_sound(int event);
566
567 /* Forward declarations of Term hooks, etc. */
568 static void Term_init_acn(term *t);
569 static errr Term_user_acn(int n);
570
571 #ifndef FULLSCREEN_ONLY
572 static errr Term_curs_acn(int x, int y);
573 static errr Term_text_acn(int x, int y, int n, byte a, cptr s);
574 static errr Term_xtra_acn(int n, int v);
575 static errr Term_wipe_acn(int x, int y, int n);
576 static errr Term_xtra_acn_check(void);
577 static errr Term_xtra_acn_event(void);
578 static errr Term_xtra_acn_react(void);
579 #endif /* FULLSCREEN_ONLY */
580
581 static errr Term_curs_acnFS(int x, int y);
582 static errr Term_text_acnFS(int x, int y, int n, byte a, cptr s);
583 static errr Term_xtra_acnFS(int n, int v);
584 static errr Term_wipe_acnFS(int x, int y, int n);
585 static errr Term_xtra_acn_checkFS(void);
586 static errr Term_xtra_acn_clearFS(void);
587 static errr Term_xtra_acn_eventFS(void);
588 static errr Term_xtra_acn_reactFS(int force);
589
590 #ifdef USE_DA
591 /* Forward declarations of the memory stuff */
592 static void init_memory(int, int);
593 #endif
594
595 /* Forward declarations of the alarm stuff */
596 static void check_alarm(void);
597 #ifndef FULLSCREEN_ONLY
598 static void trigger_alarm_desktop(void);
599 #endif /* FULLSCREEN_ONLY */
600 static void ack_alarm(void);
601 static void write_alarm_choices(void);
602 static void read_alarm_choices(void);
603
604
605 /* This just shows some debugging info (if enabled with FE_DEBUG_INFO) */
606 static void show_debug_info(void);
607
608
609
610 /* File-caching functions (if enabled at compile time) */
611 #ifdef USE_FILECACHE
612 FILE *cached_fopen(char *name, char *mode);
613 errr cached_fclose(FILE *fch);
614 errr cached_fgets(FILE *fch, char *buffer, int max_len);
615 #endif
616
617 /*
618 | These functions act as malloc/free, but (if possible) using memory
619 | in the 'Game' Dynamic Area created by init_memory()
620 | We attach these functions to the ralloc_aux and rnfree_aux hooks
621 | that z-virt.c provides.
622 */
623 #ifdef USE_DA
624 static vptr g_malloc(huge size);
625 static vptr g_free(vptr blk);
626 #else
627 #define g_malloc(size) malloc(size);
628 #define g_free(block) free(block);
629 #endif
630
631 /*
632 | These functions act as malloc/free, but (if possible) using memory
633 | in the 'Fonts' Dynamic Area created by init_memory()
634 */
635 #ifdef USE_DA
636 static void* f_malloc(size_t size);
637 static void f_free(void *blk);
638 #else
639 #define f_malloc(size) malloc(size);
640 #define f_free(block) free(block);
641 #endif
642
643 /*
644 | These two functions perpetrate great evil to stop IClear from mucking
645 | with the cursor keys in fullscreen mode.
646 */
647 static void iclear_hack(void);
648 static void remove_iclear_hack(void);
649
650 /*
651 | We use this to locate the choices file(s)...
652 */
653 static char *find_choices(int write);
654 static char *find_choices_mirror(void);
655 static char *find_alarmfile(int write);
656
657
658
659 /*
660 | This function is supplied as a wrapper to the save_player function.
661 |
662 | Its purpose is to change the filename that the game will be saved with
663 | the leafname "!!PANIC!!" so that panic saves that break the savefile
664 | won't overwrite the original savefile.
665 |
666 | To get this to work, you'll need to ammend files.c and change the call
667 | to save_player in the panic save function(s) (search for "panic save")
668 | to a call to save_player_panic_acn. You can declare a prototype for
669 | the function if you like.
670 */
671
save_player_panic_acn(void)672 extern int save_player_panic_acn(void)
673 {
674 char *e, *l;
675
676 /* Find the final / in the savefile name */
677 for (l = e = savefile; *e; e++)
678 if (*e == '/')
679 {
680 l = e + 1;
681 }
682
683 /* Write over the current leaf with the special panic one */
684 strcpy(l, "!!PANIC!!");
685
686 /* save the game */
687 return save_player();
688 }
689
690
691 /*--------------------------------------------------------------------------*/
692 /* Error reporting, etc. */
693 /*--------------------------------------------------------------------------*/
694
695
696 /* Tell the user something important */
plog_hook(cptr str)697 static void plog_hook(cptr str)
698 {
699 Msgs_Report(1, "err.plog", str);
700 }
701
702 /* Tell the user something, then quit */
quit_hook(cptr str)703 static void quit_hook(cptr str)
704 {
705 /* str may be null */
706 if (str) Msgs_Report(1, "err.quit", str);
707 exit(0);
708 }
709
710 /* Tell the user something then crash ;) */
core_hook(cptr str)711 static void core_hook(cptr str)
712 {
713 Msgs_Report(1, "err.core", str);
714
715 if (game_in_progress && character_generated)
716 save_player_panic_acn();
717
718 quit(NULL);
719 }
720
debug(const char * fmt,...)721 static void debug(const char *fmt, ...)
722 {
723 va_list ap;
724 char buffer[260];
725 va_start(ap, fmt);
726 vsprintf(buffer, fmt, ap);
727 va_end(ap);
728 plog(buffer);
729 }
730
731
732
733 /*
734 static void oserror_handler( int sig )
735 {
736 core(_kernel_last_oserror()->errmess);
737 }
738 */
739
740
741 /*--------------------------------------------------------------------------*/
742 /* File handling */
743 /*--------------------------------------------------------------------------*/
744
myFile_Open(const char * name,int mode)745 static int myFile_Open(const char *name, int mode)
746 {
747 int handle;
748 if (SWI(2, 1, SWI_OS_Find, mode, name, /**/ &handle))
749 return 0;
750 return handle;
751 }
752
myFile_Size(const char * name)753 static int myFile_Size(const char *name)
754 {
755 int size, type;
756 if (SWI(2, 5, SWI_OS_File, 17, name, /**/ &type, 0, 0, 0, &size))
757 return -2;
758 return type ? size : -1;
759 }
760
myFile_Close(const int handle)761 static os_error *myFile_Close(const int handle)
762 {
763 return SWI(2, 0, SWI_OS_Find, 0, handle);
764 }
765
myFile_Seek(const int handle,const int offset)766 static os_error *myFile_Seek(const int handle, const int offset)
767 {
768 return SWI(3, 0, SWI_OS_Args, 1, handle, offset);
769 }
770
myFile_WriteBytes(const int handle,const void * buf,const int n)771 static int myFile_WriteBytes(const int handle, const void *buf, const int n)
772 {
773 int ntf;
774 if (SWI(4, 4, SWI_OS_GBPB, 2, handle, buf, n, /**/ NULL, NULL, NULL, &ntf))
775 return n;
776 return ntf;
777 }
778
myFile_ReadBytes(const int handle,void * buf,const int n)779 static int myFile_ReadBytes(const int handle, void *buf, const int n)
780 {
781 int ntf;
782 if (SWI(4, 4, SWI_OS_GBPB, 4, handle, buf, n, /**/ NULL, NULL, NULL, &ntf))
783 return n;
784 return ntf;
785 }
786
myFile_SetType(const char * n,const int type)787 static os_error *myFile_SetType(const char *n, const int type)
788 {
789 return SWI(3, 0, SWI_OS_File, 18, n, type);
790 }
791
792
myFile_Extent(const int handle)793 static int myFile_Extent(const int handle)
794 {
795 int ext;
796 if (SWI(2, 3, SWI_OS_Args, 2, handle, /**/ NULL, NULL, &ext))
797 return -1;
798 return ext;
799 }
800
801
802 /*
803 | Determine if one file is newer than another.
804 |
805 | The filenames should be specified in RISC OS style.
806 |
807 | Returns -1 if 'a' is newer than 'b'.
808 */
file_is_newer(const char * a,const char * b)809 static int file_is_newer(const char *a, const char *b)
810 {
811 os_error *e;
812 struct
813 {
814 unsigned int msw;
815 unsigned int lsw;
816 }
817 a_time;
818 struct
819 {
820 unsigned int msw;
821 unsigned int lsw;
822 }
823 b_time;
824 int a_type, b_type;
825
826 /* Get the datestamp of the 'a' file */
827 e = SWI(2, 4, SWI_OS_File,
828 /* In */
829 17, (int)a,
830 /* Out */
831 &a_type, /* object type */
832 NULL, &(a_time.msw), /* Load Addr */
833 &(a_time.lsw) /* Exec Addr */
834 );
835 if (e)
836 {
837 core(e->errmess);
838 }
839
840
841 /* Get the datestamp of the 'b' file */
842 e = SWI(2, 4, SWI_OS_File,
843 /* In */
844 17, (int)b,
845 /* Out */
846 &b_type, /* object type */
847 NULL, &(b_time.msw), /* Load Addr */
848 &(b_time.lsw) /* Exec Addr */
849 );
850 if (e)
851 {
852 core(e->errmess);
853 }
854
855 /* If 'b' doesn't exist then 'b' is OOD. */
856 if (!b_type)
857 {
858 return -1;
859 }
860 /* If 'a' doesn't exist then 'b' isn't OOD. (?) */
861 if (!a_type)
862 {
863 return 0;
864 }
865
866 /* Compare the timestamps (assume that the files are typed) */
867 if ((a_time.msw & 0xff) >= (b_time.msw & 0xff))
868 if ((a_time.lsw) > (b_time.lsw))
869 return -1; /* OOD */
870 return 0; /* Not OOD */
871 }
872
873
874 /*
875 | As fprintf, but outout to all files (if their handles are non zero).
876 | NB: void type.
877 */
f2printf(FILE * a,FILE * b,const char * fmt,...)878 static void f2printf(FILE *a, FILE *b, const char *fmt, ...)
879 {
880 va_list ap;
881 char buffer[2048];
882 va_start(ap, fmt);
883 vsprintf(buffer, fmt, ap);
884 va_end(ap);
885 if (a)
886 {
887 fprintf(a, buffer);
888 }
889 if (b)
890 {
891 fprintf(b, buffer);
892 }
893 va_end(ap);
894 }
895
896
897
898
899 /*--------------------------------------------------------------------------*/
900 /* Clean up (ie. close files, etc). */
901 /*--------------------------------------------------------------------------*/
902
final_acn(void)903 static void final_acn(void)
904 {
905 int i;
906
907 for (i = 0; i < openfiles; i++)
908 myFile_Close(filehandle[i]);
909
910 if (fullscreen_mode)
911 {
912 /* Restore the screen mode */
913 Wimp_SetMode(old_screenmode);
914
915 /* Restore the various soft keys */
916 set_keys(FALSE);
917
918 /*
919 | Hack: Early WIMP versions do the "Press SPACE" thing, or something
920 | odd. It's bloody annoying, whatever it is...
921 */
922 if (event_wimpversion < 300)
923 Wimp_CommandWindow(-1);
924 }
925
926 if (flush_scrap && *scrap_path)
927 {
928 char tmp[512];
929 strcpy(tmp, scrap_path);
930 tmp[strlen(tmp) - 1] = 0; /* Remove trailing dot */
931 SWI(4, 0, SWI_OS_FSControl, 27, tmp, 0, 1); /* ie. "*Wipe <scrapdir> r~c~v~f" */
932 }
933
934 #ifdef FULLSCREEN_ONLY
935 Wimp_CommandWindow(-1);
936 #endif /* FULLSCREEN_ONLY */
937
938 Stop_Hourglass;
939 }
940
941
942 /*--------------------------------------------------------------------------*
943 | Various UNIX-like support funtions |
944 *--------------------------------------------------------------------------*/
945
946 /*
947 | Hack: determine whether filenames should be truncated to 10 chars or not.
948 |
949 | Needed since RO2 (and RO3 with Truncate configured off) will return
950 | errors instead of automatically truncating long filenames.
951 */
truncate_names(void)952 static int truncate_names(void)
953 {
954 int r1, r2;
955
956 /* First, check the OS version */
957 OS_Byte(osbyte_READOSIDENTIFIER, 0x00, 0xff, &r1, &r2);
958
959 /* Assume that we need to truncate if running under RO2 */
960 if (r1 == 0xa1 || r1 == 0xa2)
961 return TRUE;
962
963 /* Okay, so we've got RO3 (or later), so check the CMOS RAM */
964 OS_Byte(osbyte_READCMOSRAM, 28, 0, &r1, &r2);
965
966 /* Bit 0 of byte 28 is the Truncate flag */
967 return !(r2 & 1);
968 }
969
970
971 /*
972 | The PathName translation is now done by two separate functions:
973 | unixify_name() and riscosify_name().
974 |
975 | This is done because only the UNIX=>RISCOS translation should
976 | ever affect the length of the leafname (ie. by truncating it to
977 | 10 chars if necessary).
978 |
979 | Note that the two functions are identical but for the truncation
980 | check so all that's really been done is that translate_name() now
981 | takes an extra argument: 'trunc' that controls whether truncation
982 | is applied, and riscosify and unixify just call translate_name().
983 */
translate_name(const char * path,int trunc)984 static char *translate_name(const char *path, int trunc)
985 {
986 static char buf[260];
987 char c, *p;
988
989 /* Copy 'path' into 'buf', swapping dots and slashes */
990 p = buf; /* Output position */
991 do
992 {
993 c = *path++;
994 if (c == '/')
995 c = '.';
996 else if (c == '.')
997 c = '/';
998 *p++ = c;
999 }
1000 while (c); /* Terminator /is/ copied */
1001
1002 /*
1003 | When saving a game, the old game is renamed as
1004 | "SavedGame.old", the new one is saved as "SavedGame.new",
1005 | "SavedGame.old" is deleted, "SavedGame.new" is renamed
1006 | as "SavedGame". This will go wrong on a Filecore based filing
1007 | system if the saved game has a leafname > 8 chars.
1008 */
1009
1010 if ((p = strstr(buf, "/old")) == NULL)
1011 {
1012 p = strstr(buf, "/new");
1013 }
1014 if (!p)
1015 {
1016 ftype = 0xffd;
1017 }
1018 else
1019 {
1020 char *q = strrchr(buf, '.');
1021 if (q)
1022 if (p - q > 6)
1023 {
1024 memmove(q + 6, p, 5);
1025 }
1026 ftype = vfiletype;
1027 }
1028
1029 /*
1030 | Hack: Do we need to truncate the leafname?
1031 */
1032 if (trunc)
1033 {
1034 if (truncate_names())
1035 {
1036 char *a, *b;
1037 /*
1038 | Assume that only the leafname needs attention
1039 | (this should be true for any variant)
1040 */
1041 for (a = b = buf; *a; a++)
1042 if (*a == '.')
1043 b = a + 1;
1044 /*
1045 | Now b points to the start of the leafname.
1046 | If the leafname is >10 chars, write over the 10th with a
1047 | terminator.
1048 */
1049 if (strlen(b) > 10)
1050 {
1051 b[10] = 0;
1052 };
1053 }
1054 }
1055
1056 return buf;
1057 }
1058
1059
riscosify_name(const char * path)1060 extern char *riscosify_name(const char *path)
1061 {
1062 return translate_name(path, TRUE);
1063 }
1064
unixify_name(const char * path)1065 static char *unixify_name(const char *path)
1066 {
1067 return translate_name(path, FALSE);
1068 }
1069
1070
1071 /*--------------------------------------------------------------------------*/
1072
1073
1074 /* Open a file [as fopen()] but translate the requested filename first */
1075
my_fopen(const char * f,const char * m)1076 FILE *my_fopen(const char *f, const char *m)
1077 {
1078 FILE *fp;
1079 char *n = riscosify_name(f); /* translate for RO */
1080
1081 /* Try to open the file */
1082 fp = fopen(n, m);
1083
1084 /* If it succeded and the file was opened for binary output
1085 | then set the type according to the 'ftype' hack.
1086 | NB: This will fail on some filing systems.
1087 */
1088
1089 if (fp && strstr(m, "wb"))
1090 {
1091 myFile_SetType(n, ftype);
1092 }
1093
1094 return fp;
1095 }
1096
1097
1098
1099
1100 /* Close a file, a la fclose() */
1101
my_fclose(FILE * fp)1102 void my_fclose(FILE *fp)
1103 {
1104 /* Close the file, return 1 for an error, 0 otherwise */
1105 fclose(fp);
1106 }
1107
1108
1109 /* Open/Create a file */
1110
fd_make(cptr file,int mode)1111 int fd_make(cptr file, int mode)
1112 {
1113 char *real_path;
1114 int handle;
1115
1116 /* Translate the filename into a RISCOS one */
1117 real_path = riscosify_name(file);
1118
1119 /* Try to OPENOUT the file (no path, error if dir or not found) */
1120 handle = myFile_Open(real_path, 0x8f);
1121
1122 /* Check for failure */
1123 if (!handle)
1124 {
1125 return -1;
1126 }
1127
1128 /* Try to set the filetype according to the ftype hack */
1129 myFile_SetType(real_path, ftype);
1130
1131 /* We keep track of up to 16 open files at any given time */
1132 if (openfiles < 16)
1133 filehandle[openfiles++] = handle;
1134
1135 return (handle);
1136 }
1137
1138
1139 /* Delete a file [as remove()] */
fd_kill(cptr file)1140 errr fd_kill(cptr file)
1141 {
1142 return remove(riscosify_name(file)) ? 1 : 0;
1143 }
1144
1145
1146 /* Rename a file [as rename()] */
fd_move(cptr old,cptr new)1147 errr fd_move(cptr old, cptr new)
1148 {
1149 char new_[260];
1150 strcpy(new_, riscosify_name(new));
1151 return rename(riscosify_name(old), new_) ? 1 : 0;
1152 }
1153
1154 /* Open a file */
fd_open(cptr path,int flags)1155 int fd_open(cptr path, int flags)
1156 {
1157 int handle = 0;
1158 char *real_path = riscosify_name(path);
1159
1160 switch (flags & 0x0f)
1161 {
1162 case O_RDONLY: /* Read only */
1163 handle = myFile_Open(real_path, 0x4f);
1164 break;
1165 case O_WRONLY: /* Write only */
1166 case O_RDWR: /* Read/Write */
1167 handle = myFile_Open(real_path, 0xcf);
1168 }
1169
1170 /* Check for failure */
1171 if (!handle)
1172 {
1173 return (-1);
1174 }
1175
1176 /* Keep track of upto 16 open files... */
1177 if (openfiles < 16)
1178 filehandle[openfiles++] = handle;
1179
1180 return (handle);
1181 }
1182
1183
1184 /* Close a file opened with fd_make or fd_open */
fd_close(int handle)1185 errr fd_close(int handle)
1186 {
1187 int i;
1188
1189 if (handle <= 0)
1190 {
1191 return -1;
1192 } /* Illegal handle */
1193
1194 /* Try to close the file */
1195 if (myFile_Close(handle))
1196 {
1197 return 1;
1198 }
1199
1200 /* Mark the file as closed in our array of file handles */
1201 openfiles--;
1202 /* Find the entry in the array (if it exists) */
1203 for (i = 0; i < 16; i++)
1204 if (filehandle[i] == handle)
1205 {
1206 break;
1207 }
1208 /* Shuffle the remaining entries down */
1209 for (; i < openfiles; i++)
1210 filehandle[i] = filehandle[i + 1];
1211
1212 return 0; /* Sucess */
1213 }
1214
1215
1216
1217 /* Read some bytes from a file */
fd_read(int handle,char * buf,huge nbytes)1218 errr fd_read(int handle, char *buf, huge nbytes)
1219 {
1220 int unread;
1221
1222 if (handle <= 0)
1223 {
1224 return -1;
1225 } /* Illegal handle */
1226 unread = myFile_ReadBytes(handle, buf, (int)nbytes);
1227
1228 return unread ? 1 : 0;
1229 }
1230
1231
1232 /* Write some bytes to a file */
fd_write(int handle,const char * buf,huge nbytes)1233 errr fd_write(int handle, const char *buf, huge nbytes)
1234 {
1235 int unwritten;
1236
1237 if (handle <= 0)
1238 {
1239 return -1;
1240 } /* Illegal handle */
1241 unwritten = myFile_WriteBytes(handle, (const void *)buf, (int)nbytes);
1242
1243 return unwritten ? 1 : 0;
1244 }
1245
1246
1247 /* Seek in a file */
fd_seek(int handle,huge offset)1248 errr fd_seek(int handle, huge offset)
1249 {
1250 os_error *e;
1251
1252 if (handle <= 0)
1253 {
1254 return -1;
1255 } /* Illegal handle */
1256 e = myFile_Seek(handle, (int)offset);
1257
1258 return e ? 1 : 0;
1259 }
1260
1261
1262 /* RISC OS provides no file locking facilities, so: */
fd_lock(int handle,int what)1263 errr fd_lock(int handle, int what)
1264 {
1265 return 0;
1266 }
1267
1268
1269 /* Get a temporary filename */
path_temp(char * buf,size_t max)1270 errr path_temp(char *buf, size_t max)
1271 {
1272
1273 /*
1274 | New in 1.25 - use the scrap path we decided on earlier, or
1275 | fall back on tmpnam() if that fails for some reason.
1276 */
1277 if (*scrap_path)
1278 {
1279 time_t t;
1280 int m;
1281 char tmp[512];
1282
1283 time(&t);
1284 for (m = 0; m < 80; m++)
1285 {
1286 sprintf(tmp, "%s0x%08x", scrap_path, (int)t + m);
1287 if (myFile_Size(tmp) == -1)
1288 {
1289 break;
1290 }
1291 }
1292
1293 if (m < 80)
1294 {
1295 strncpy(buf, unixify_name(tmp), max);
1296 return 0;
1297 }
1298 }
1299
1300 strncpy(buf, unixify_name(tmpnam(NULL)), max);
1301 return 0;
1302 }
1303
1304
1305
1306 /*
1307 * Create a new path by appending a file (or directory) to a path
1308 *
1309 * This requires no special processing on simple machines, except
1310 * for verifying the size of the filename, but note the ability to
1311 * bypass the given "path" with certain special file-names.
1312 *
1313 * Note that the "file" may actually be a "sub-path", including
1314 * a path and a file.
1315 *
1316 * Note that this function yields a path which must be "parsed"
1317 * using the "parse" function above.
1318 */
path_build(char * buf,int max,cptr path,cptr file)1319 void path_build(char *buf, int max, cptr path, cptr file)
1320 {
1321 /* Special file */
1322 if (file[0] == '~')
1323 {
1324 /* Use the file itself */
1325 strnfmt(buf, max, "%s", file);
1326 }
1327
1328 /* Absolute file, on "normal" systems */
1329 else if (prefix(file, PATH_SEP) && !streq(PATH_SEP, ""))
1330 {
1331 /* Use the file itself */
1332 strnfmt(buf, max, "%s", file);
1333 }
1334
1335 /* No path given */
1336 else if (!path[0])
1337 {
1338 /* Use the file itself */
1339 strnfmt(buf, max, "%s", file);
1340 }
1341
1342 /* Path and File */
1343 else
1344 {
1345 /* Build the new path */
1346 strnfmt(buf, max, "%s%s%s", path, PATH_SEP, file);
1347 }
1348 }
1349
1350
1351
1352 /*--------------------------------------------------------------------------*/
1353
1354
1355
1356
1357
1358 /*--------------------------------------------------------------------------*/
1359 /* Font Functions */
1360 /*--------------------------------------------------------------------------*/
1361
1362 /*
1363 | Cache the system font as fonts[0]
1364 | Returns 1 for sucess or 0 for failure.
1365 | NB: The n_bpp data is *not* cached, just the 1bpp data and font info.
1366 | Also, the usage is never affected.
1367 */
cache_system_font(void)1368 static int cache_system_font(void)
1369 {
1370 ZapFont *sys = SYSTEM_FONT;
1371 ZapRedrawBlock zrb;
1372 char work_area[16];
1373 int i;
1374
1375 /* Cache the system font (as fonts[0]) */
1376 if (sys->bpp_1)
1377 {
1378 f_free(sys->bpp_1);
1379 sys->bpp_1 = 0;
1380 }
1381 sys->bpp_1 = f_malloc(8 * 256); /* 2K */
1382 if (!sys->bpp_1)
1383 {
1384 return 0;
1385 }
1386
1387 /* Mung so that undefined characters show up as inverted ?s */
1388 work_area[3] = '?';
1389 SWI(2, 0, SWI_OS_Word, 10, work_area + 3);
1390 for (i = 4; i < 12; i++)
1391 work_area[i] ^= 255; /* invert colours */
1392 SWI(4, 0, SWI_ZapRedraw_ReverseBitmaps, 0, work_area + 4, work_area + 4, 8);
1393 for (i = 0; i < 0x20; i++)
1394 memcpy(((char *)sys->bpp_1) + i * 8, work_area + 4, 8);
1395
1396 /* Read the system font */
1397 zrb.r_workarea = work_area;
1398 SWI(2, 0, SWI_ZapRedraw_ReadSystemChars, sys->bpp_1, &zrb);
1399
1400 /* Set up some little bits of info */
1401 sys->name = (char *) "<System>";
1402 sys->w = sys->h = 8;
1403 sys->f = 0;
1404 sys->l = 255;
1405
1406 return 1;
1407 }
1408
1409
1410
1411 /*
1412 | Prepare the font system
1413 */
initialise_fonts(void)1414 static void initialise_fonts(void)
1415 {
1416 /* Initialise the array */
1417 memset(fonts, 0, sizeof(fonts)); /* Clear to zeroes */
1418
1419 /* Cache the system font */
1420 cache_system_font();
1421 fonts[0].usage = 0; /* No users */
1422 }
1423
1424
1425 #ifndef FULLSCREEN_ONLY
1426 /*
1427 | Find a font (by name) in the array.
1428 | Returns 0 if the font isn't loaded, or a ZapFont* for it if it is.
1429 */
find_font_by_name(char * name)1430 static ZapFont *find_font_by_name(char *name)
1431 {
1432 int i;
1433 for (i = 0; i <= MAX_TERM_DATA; i++)
1434 if (fonts[i].name)
1435 if (!strcmp(fonts[i].name, name))
1436 return &(fonts[i]);
1437 return NULL;
1438 }
1439
1440 /*
1441 | Find a free slot in the fonts array
1442 */
find_free_font(void)1443 static ZapFont *find_free_font(void)
1444 {
1445 int i;
1446 for (i = 1; i <= MAX_TERM_DATA; i++)
1447 if (!fonts[i].name)
1448 {
1449 return &(fonts[i]);
1450 }
1451 return NULL;
1452 }
1453
1454
1455
1456 /*
1457 | Load a font from disc and set up the header info, etc.
1458 | NB: doesn't cache the nbpp data, just the 1bpp data.
1459 | (Sets usage to 1)
1460 | Returns NULL if failed.
1461 */
load_font(char * name,ZapFont * f)1462 static ZapFont *load_font(char *name, ZapFont *f)
1463 {
1464 int handle, extent;
1465 char path[260];
1466 struct
1467 {
1468 char id[8];
1469 int w, h, f, l, r1, r2;
1470 }
1471 header;
1472 char *font_path;
1473 char *t;
1474 char *real_name = name; /* need to preserve this */
1475
1476 /*
1477 | 1.10 - the first element of the name determines the path to load
1478 | the font from.
1479 */
1480
1481 /* The font paths start <RISCOS_VARIANT>$ */
1482 t = path + sprintf(path, "%s$", RISCOS_VARIANT);
1483
1484 /* Copy the path specifier and move 'name' past it */
1485 for (; *name != '.'; *t++ = *name++) ;
1486
1487 /* After this, the name now points to the font name proper */
1488 name++;
1489
1490 /* Append the end of the path name */
1491 strcpy(t, "$FontPath");
1492
1493 /* Get the path setting */
1494 font_path = getenv(path);
1495 if (!font_path || !*font_path)
1496 strcpy(path, "null:$.");
1497 else
1498 {
1499 strcpy(path, font_path);
1500 for (t = path; *t > ' '; t++)
1501 ;
1502 if (t[-1] != '.' && t[-1] != ':')
1503 {
1504 *t++ = '.';
1505 }
1506 *t = 0;
1507 }
1508 strcat(path, name);
1509
1510
1511 /* Open the file */
1512 handle = myFile_Open(path, 0x4f);
1513 if (!handle)
1514 {
1515 return NULL;
1516 }
1517
1518 /* Read the header */
1519 if (myFile_ReadBytes(handle, &header, sizeof(header)))
1520 {
1521 myFile_Close(handle);
1522 return NULL;
1523 }
1524
1525 /* Check that it's a zapfont */
1526 if (strncmp(header.id, "ZapFont\r", 8))
1527 {
1528 myFile_Close(handle);
1529 return NULL;
1530 }
1531
1532 /* Calculate the size of the 1bpp data */
1533 extent = myFile_Extent(handle) - sizeof(header);
1534
1535 /* Allocate the storage for the 1bpp data */
1536 f->bpp_1 = f_malloc(extent);
1537 if (!f->bpp_1)
1538 {
1539 myFile_Close(handle);
1540 return NULL;
1541 }
1542
1543 /* Load the 1bpp data */
1544 if (myFile_ReadBytes(handle, f->bpp_1, extent))
1545 {
1546 f_free(f->bpp_1);
1547 f->bpp_1 = 0;
1548 myFile_Close(handle);
1549 return NULL;
1550 }
1551
1552 /* Close the file and set the header, etc. */
1553 myFile_Close(handle);
1554 f->name = f_malloc(strlen(real_name) + 1);
1555 if (!f->name)
1556 {
1557 f_free(f->bpp_1);
1558 f->bpp_1 = 0;
1559 return NULL;
1560 }
1561
1562 strcpy(f->name, real_name);
1563 f->w = header.w;
1564 f->h = header.h;
1565 f->f = header.f;
1566 f->l = header.l;
1567 f->usage = 1;
1568
1569 return f;
1570 }
1571
1572
1573
1574
1575 /*
1576 | Cache a font at a suitable number of bpp for the current mode
1577 | Returns 0 for failure, 1 for sucess.
1578 | If the call fails then the font's bpp_n entry will be NULL.
1579 */
cache_font_for_mode(ZapFont * f)1580 static int cache_font_for_mode(ZapFont *f)
1581 {
1582 ZapRedrawBlock b;
1583 char work_area[128];
1584 int size;
1585
1586 if (!f)
1587 {
1588 return 0;
1589 }
1590 if (!f->bpp_1)
1591 {
1592 return 0;
1593 }
1594
1595 b.r_workarea = work_area;
1596 SWI(2, 0, SWI_ZapRedraw_ReadVduVars, 0, &b);
1597
1598 b.r_workarea = work_area; /* Paranoia */
1599 b.r_charh = f->h;
1600 b.r_charw = f->w;
1601 SWI(4, 4, SWI_ZapRedraw_CachedCharSize, b.r_bpp, 0, f->w, f->h,
1602 NULL, NULL, &(b.r_cbpl), &(b.r_cbpc));
1603
1604 size = 256 * b.r_cbpc;
1605 if (f->bpp_n)
1606 {
1607 f_free(f->bpp_n);
1608 f->bpp_n = NULL;
1609 }
1610 f->bpp_n = f_malloc(size);
1611 if (!f->bpp_n)
1612 {
1613 return 0;
1614 }
1615
1616 b.r_workarea = work_area; /* Paranoia */
1617 b.r_caddr = f->bpp_n;
1618 SWI(5, 0, SWI_ZapRedraw_ConvertBitmap, 0, &b, 0, 255, f->bpp_1);
1619
1620 return 1;
1621 }
1622
1623
1624
1625 /*
1626 | Stop using a font.
1627 | If the font's usage drops to zero then the font data is purged.
1628 */
lose_font(ZapFont * f)1629 static void lose_font(ZapFont *f)
1630 {
1631 if (--f->usage)
1632 {
1633 /*debug("Losing font %s (still cached)",f->name); */
1634 return;
1635 }
1636 /*debug("Losing font %s (no longer in use)",f->name); */
1637 f_free(f->name);
1638 f_free(f->bpp_1);
1639 if (f->bpp_n)
1640 {
1641 f_free(f->bpp_n);
1642 }
1643 memset(f, 0, sizeof(ZapFont));
1644 }
1645
1646
1647 /*
1648 | Get a font.
1649 */
find_font(char * name)1650 static ZapFont *find_font(char *name)
1651 {
1652 ZapFont *f;
1653
1654 /* Check to see if it's already loaded */
1655 f = find_font_by_name(name);
1656 if (f)
1657 {
1658 /*debug("Find font %s (already cached)",name); */
1659 f->usage++;
1660 if (f == SYSTEM_FONT)
1661 {
1662 if (!cache_system_font())
1663 core("Failed to cache system font!");
1664 if (!cache_font_for_mode(SYSTEM_FONT))
1665 core("Failed to cache system font!");
1666 }
1667 return f;
1668 }
1669
1670 /* Ok, now check to see if there's a free slot for it */
1671 f = find_free_font();
1672 if (!f)
1673 {
1674 return NULL;
1675 } /* Oh dear :( */
1676
1677 /* Load the font */
1678 /*debug("Find font %s (loading)",name); */
1679 f = load_font(name, f);
1680 if (f)
1681 {
1682 if (!cache_font_for_mode(f))
1683 return NULL;
1684 return f;
1685 }
1686 return NULL;
1687 }
1688
1689
1690
1691
1692 /*
1693 | Cache the n_bpp data for all the active fonts (including system)
1694 */
cache_fonts(void)1695 static void cache_fonts(void)
1696 {
1697 int i;
1698 for (i = 0; i <= MAX_TERM_DATA; i++)
1699 if (fonts[i].name)
1700 if (!cache_font_for_mode(&(fonts[i])))
1701 core("Failed to (re)cache font tables");
1702 }
1703
1704
1705
1706
1707
1708
1709 typedef struct
1710 {
1711 int load, exec, size, attr, type;
1712 char name[4]; /* Actual size is unknown */
1713 }
1714 osgbpb10_block;
1715
1716
leafname(char * path)1717 static char *leafname(char *path)
1718 {
1719 char *s = path + strlen(path);
1720 while (--s > path)
1721 if (*s == '.' || *s == ':')
1722 {
1723 return s + 1;
1724 }
1725 return path;
1726 }
1727
1728 /*
1729 | NB: This function is recursive.
1730 */
make_zfont_menu(char * dir)1731 static menu_ptr make_zfont_menu(char *dir)
1732 {
1733 int entries, entry;
1734 int read, offset;
1735 unsigned int max_width;
1736 menu_ptr m;
1737 menu_item *mi;
1738 char *temp;
1739 osgbpb10_block *item_info;
1740 char buffer[1024]; /* 1Kb buffer */
1741
1742 /* Count the entries in the directory */
1743 entries = read = offset = 0;
1744 while (offset != -1)
1745 {
1746 if (SWI(7, 5, SWI_OS_GBPB, 10, dir, buffer, 77, offset, 1024, 0,
1747 NULL, NULL, NULL, &read, &offset))
1748 {
1749 offset = -1;
1750 read = 0;
1751 }
1752 entries += read;
1753 }
1754
1755 if (!entries)
1756 {
1757 return NULL;
1758 }
1759
1760 /* Allocate a big enough area of storage for the number of entries */
1761 m = f_malloc(sizeof(menu_block) + entries * sizeof(menu_item));
1762 if (!m)
1763 {
1764 return NULL;
1765 }
1766 memset(m, 0, sizeof(menu_block) + entries * sizeof(menu_item));
1767
1768 /* Set up the menu header */
1769 strncpy(m->title, leafname(dir), 12);
1770 m->titlefore = 7;
1771 m->titleback = 2;
1772 m->workfore = 7;
1773 m->workback = 0;
1774 m->height = 44;
1775 m->gap = 0;
1776 mi = (menu_item *) (((int)m) + sizeof(menu_block));
1777 max_width = strlen(m->title);
1778
1779 entry = 0;
1780
1781 /* Read the entries */
1782 read = offset = 0;
1783 while (offset != -1)
1784 {
1785 if (SWI(7, 5, SWI_OS_GBPB, 10, dir, buffer, 77, offset, 1024, 0,
1786 NULL, NULL, NULL, &read, &offset))
1787 {
1788 offset = -1;
1789 read = 0;
1790 /*free(m);return NULL; */
1791 }
1792
1793 item_info = (osgbpb10_block *) buffer;
1794
1795 /* Create a menu item for each entry read (if it fits) */
1796 while (read-- > 0)
1797 {
1798 switch (item_info->type)
1799 {
1800 case 1: /* File */
1801 if ((item_info->load & 0xffffff00) == 0xfffffd00)
1802 {
1803 /* Data file */
1804 mi[entry].submenu.value = -1;
1805 mi[entry].iconflags.data.text = 1;
1806 mi[entry].iconflags.data.filled = 1;
1807 mi[entry].iconflags.data.foreground = 7;
1808 mi[entry].iconflags.data.background = 0;
1809 strncpy(mi[entry].icondata.text, item_info->name, 12);
1810 if (strlen(mi[entry].icondata.text) > max_width)
1811 max_width = strlen(mi[entry].icondata.text);
1812 entry++;
1813 }
1814 break;
1815 case 2: /* Directory */
1816 case 3: /* Image */
1817 {
1818 menu_ptr sub;
1819 char new_path[260];
1820 if (strchr(":.", dir[strlen(dir) - 1]))
1821 sprintf(new_path, "%s%s", dir, item_info->name);
1822 else
1823 sprintf(new_path, "%s.%s", dir, item_info->name);
1824 sub = make_zfont_menu(new_path);
1825 if (sub)
1826 {
1827 /* Add the submenu */
1828 mi[entry].submenu.menu = sub;
1829 mi[entry].iconflags.data.text = 1;
1830 mi[entry].iconflags.data.filled = 1;
1831 mi[entry].iconflags.data.foreground = 7;
1832 mi[entry].iconflags.data.background = 0;
1833 strncpy(mi[entry].icondata.text, item_info->name, 12);
1834 if (strlen(mi[entry].icondata.text) > max_width)
1835 max_width = strlen(mi[entry].icondata.text);
1836 entry++;
1837 }
1838 }
1839 break;
1840 }
1841 temp = ((char *)item_info) + 20;
1842 while (*temp++) ;
1843 item_info = (osgbpb10_block *) ((((int)temp) + 3) & ~3);
1844 }
1845 }
1846
1847 if (entry)
1848 {
1849 m->width = (max_width + 2) * 16;
1850 mi[entry - 1].menuflags.data.last = 1;
1851 /*
1852 | We could possibly realloc() the storage to fit the
1853 | actual no. of entries read, but this is probably more
1854 | trouble than it's worth.
1855 */
1856 }
1857 else
1858 {
1859 /*
1860 | No point in returning an empty menu.
1861 */
1862 f_free(m);
1863 m = NULL;
1864 }
1865
1866 return m;
1867 }
1868
1869 #endif /* FULLSCREEN_ONLY */
1870
1871
1872
1873
1874 /*--------------------------------------------------------------------------*/
1875
1876 /*
1877 | Initialise the palette stuff
1878 */
initialise_palette(void)1879 static void initialise_palette(void)
1880 {
1881 memset(a_palette, 0, sizeof(a_palette));
1882 memset(palette, 0, sizeof(palette));
1883 memset(zpalette, 0, sizeof(zpalette));
1884 }
1885
1886
1887
1888 #ifndef FULLSCREEN_ONLY
1889
1890 /*
1891 | Cache the ZapRedraw palette
1892 */
cache_palette(void)1893 static void cache_palette(void)
1894 {
1895 static ZapRedrawBlock b;
1896 char workspace[128];
1897 int i;
1898
1899 static double old_gamma = -1.0;
1900
1901 /* Idiocy check: */
1902 if (gamma < 0.01)
1903 {
1904 plog("Internal error: Attempt to apply zero gamma - recovering...");
1905 gamma = 1.00;
1906 }
1907
1908 if (gamma != old_gamma)
1909 {
1910 memset(a_palette, 0, sizeof(a_palette));
1911 old_gamma = gamma;
1912 }
1913
1914 /* Go through the palette updating any changed values */
1915 for (i = 0; i < 256; i++)
1916 {
1917 if (COLOUR_CHANGED(i))
1918 {
1919 int r, g, b;
1920 r = (int)(255.0 *
1921 pow(angband_color_table[i][1] / 255.0, 1.0 / gamma));
1922 g = (int)(255.0 *
1923 pow(angband_color_table[i][2] / 255.0, 1.0 / gamma));
1924 b = (int)(255.0 *
1925 pow(angband_color_table[i][3] / 255.0, 1.0 / gamma));
1926 palette[i] = (b << 24) | (g << 16) | (r << 8);
1927 a_palette[i][1] = angband_color_table[i][1];
1928 a_palette[i][2] = angband_color_table[i][2];
1929 a_palette[i][3] = angband_color_table[i][3];
1930 }
1931 }
1932
1933 cursor_rgb = palette[CURSOR_COLOUR];
1934
1935 /* Cache the ZapRedraw palette for it */
1936 b.r_workarea = workspace;
1937 if (b.r_mode != screen_mode)
1938 SWI(2, 0, SWI_ZapRedraw_ReadVduVars, 0, &b);
1939 SWI(5, 0, SWI_ZapRedraw_CreatePalette, 2, &b, palette, zpalette, 256);
1940 }
1941
1942
1943
1944
1945 /*--------------------------------------------------------------------------*/
1946
1947 /*
1948 | Functions for dealing with the SaveBox
1949 */
1950
1951 /*
1952 | Create the window and claim various handlers for it
1953 */
init_save_window(void)1954 static void init_save_window(void)
1955 {
1956 /* Create the window */
1957 save_box = Window_Create("save", template_TITLEMIN);
1958
1959 /* Set the file icon */
1960 Icon_printf(save_box, SAVE_ICON, "file_%03x", vfiletype);
1961
1962 }
1963 #endif /* FULLSCREEN_ONLY */
1964
1965 /*
1966 | Hack: can't use Str.h without defining HAS_STRICMP. Rather than
1967 | require that the header files are altered we simply provide our
1968 | own strnicmp() function.
1969 */
my_strnicmp(const char * a,const char * b,int n)1970 static int my_strnicmp(const char *a, const char *b, int n)
1971 {
1972 int i;
1973
1974 n--;
1975
1976 for (i = 0; i <= n; i++)
1977 {
1978 if (tolower((unsigned char)a[i]) != tolower((unsigned char)b[i]))
1979 return tolower((unsigned char)a[i]) - tolower((unsigned char)b[i]);
1980
1981 if (a[i] == '\0')
1982 break;
1983 }
1984
1985 return 0;
1986 }
1987
1988 #ifndef FULLSCREEN_ONLY
1989 /*
1990 | This is the handler called when a 'save' occurrs.
1991 | All it does is to update the game's own savefile setting and
1992 | then (if possible) save the character.
1993 */
SaveHnd_FileSave(char * filename,void * ref)1994 static BOOL SaveHnd_FileSave(char *filename, void *ref)
1995 {
1996 char old_savefile[1024];
1997
1998 /* Hack: refuse to save if the character is dead */
1999 if (PDEADCHK)
2000 {
2001 Msgs_Report(0, "err.cheat");
2002 return FALSE;
2003 }
2004
2005 /* Hack: disallow saves to <Wimp$Scrap>* */
2006 if (!my_strnicmp("<wimp$scrap>", filename, 12))
2007 {
2008 Msgs_Report(0, "err.scrap");
2009 return FALSE;
2010 }
2011
2012 /* Preserve the old path, in case something goes wrong... */
2013 strcpy(old_savefile, savefile);
2014
2015 /* Set the new path */
2016 strcpy(savefile, unixify_name(filename));
2017
2018 /* Try a save (if sensible) */
2019 if (game_in_progress && character_generated)
2020 {
2021 if (!save_player())
2022 {
2023 Msgs_Report(0, "err.save", filename);
2024 strcpy(savefile, old_savefile);
2025 return FALSE; /* => failure */
2026 }
2027 }
2028
2029 /* Set the pathname icon */
2030 Icon_printf(save_box, SAVE_PATH, "%s", riscosify_name(savefile));
2031
2032 /* Kill the menu */
2033 Wimp_CreateMenu((menu_block *) - 1, -1, -1);
2034
2035 return TRUE; /* => Success */
2036 }
2037
2038
2039
2040 /*
2041 | Init the handlers for the savebox (eg. as a result of a menuwarning
2042 | being received for the savebox)
2043 */
2044
init_savehandlers(void)2045 static void init_savehandlers(void)
2046 {
2047 if (saveblk)
2048 {
2049 Save_ReleaseSaveHandlers(saveblk);
2050 saveblk = 0;
2051 }
2052
2053 saveblk = Save_InitSaveWindowHandler(save_box, /* Window handle */
2054 TRUE, /* it's part of a menu */
2055 FALSE, /* not a window */
2056 FALSE, /* Don't auto release the handlers */
2057 SAVE_ICON, /* The file icon */
2058 SAVE_OK, /* The OK icon */
2059 SAVE_CANCEL, /* The cancel icon */
2060 SAVE_PATH, /* The pathname icon */
2061 SaveHnd_FileSave, /* Handler to "save the file" */
2062 NULL, /* No RAM transfer support */
2063 NULL, /* No 'result handler' */
2064 100 << 10, /* Est. size (irelevant anyway) */
2065 vfiletype, /* filetype (irelevant) */
2066 NULL /* ref */
2067 );
2068 }
2069
2070
2071 /*
2072 | Handle a MenuWarning message for the savebox
2073 */
Hnd_SaveWarning(event_pollblock * pb,void * ref)2074 static BOOL Hnd_SaveWarning(event_pollblock * pb, void *ref)
2075 {
2076 os_error *e;
2077
2078 init_savehandlers();
2079
2080 /* Set the pathname */
2081 Icon_printf(save_box, SAVE_PATH, "%s", riscosify_name(savefile));
2082
2083 /* Open the submenu */
2084 e = Wimp_CreateSubMenu((menu_block *) save_box,
2085 pb->data.message.data.menuwarn.openpos.x,
2086 pb->data.message.data.menuwarn.openpos.y);
2087
2088 if (e)
2089 {
2090 Msgs_ReportFatal(0, "err.swi", __LINE__, e->errmess);
2091 }
2092
2093 return TRUE;
2094 }
2095
2096
2097 /*--------------------------------------------------------------------------*/
2098
2099
2100 /*
2101 | Initialise the r_data array
2102 | Mainly we just set up the line offset pointers and make sure that the
2103 | lines themselves are 'safe' by writing end-of-line codes to them.
2104 */
initialise_r_data(void)2105 static void initialise_r_data(void)
2106 {
2107 int *lo = (int *)r_data;
2108 char *ld;
2109 int j;
2110 for (j = 0; j < 24; j++)
2111 {
2112 lo[j] = 25 * 4 + (80 * 5 + 4) * j; /* Offset of line */
2113 ld = r_data + lo[j];
2114 *ld++ = 0; /* 0,2 == */
2115 *ld = 2; /* end of line */
2116 }
2117 lo[j] = 0; /* Terminate line index */
2118 }
2119
2120
2121
2122 /*
2123 | Create the r_data array for a term
2124 | This is typically quite fast (1ms or so on a RPC700)
2125 | so we don't bother caching r_data for each term or using the
2126 | 'frosh' concept.
2127 */
make_r_data(term_data * t)2128 static void make_r_data(term_data *t)
2129 {
2130 char **c = t->t.old->c; /* char array [24][80] */
2131 byte **a = t->t.old->a; /* attr array [24][80] */
2132 char *o;
2133 int i, j, cf;
2134
2135 /* New code: */
2136
2137 o = r_data + 25 * 4; /* First byte of r_data after line index */
2138
2139 if (force_mono)
2140 {
2141 for (j = 0; j < 24; j++)
2142 {
2143 /* Set up the line offset entry */
2144 ((int *)r_data)[j] = o - r_data;
2145
2146 for (i = 0; i < 80; i++)
2147 *o++ = a[j][i] != TERM_DARK ? c[j][i] : ' ';
2148 /* 0,2 => end of line */
2149 *o++ = 0;
2150 *o++ = 2;
2151 }
2152 }
2153 else
2154 {
2155 for (j = 0; j < 24; j++)
2156 {
2157 /* Set up the line offset entry */
2158 ((int *)r_data)[j] = o - r_data;
2159
2160 /* Each line starts in white */
2161 cf = TERM_WHITE;
2162
2163 for (i = 0; i < 80; i++)
2164 {
2165 if (a[j][i] != cf)
2166 {
2167 /* 0,6 => change FG */
2168 *o++ = 0;
2169 *o++ = 6;
2170 cf = *o++ = a[j][i];
2171 }
2172 *o++ = c[j][i];
2173 }
2174 /* 0,2 => end of line */
2175 *o++ = 0;
2176 *o++ = 2;
2177 }
2178 }
2179 }
2180
2181
2182 /*
2183 | Set up 'zrb' for the current screen mode.
2184 */
set_up_zrb_for_mode(void)2185 static void set_up_zrb_for_mode(void)
2186 {
2187 static char work_area[4096];
2188 zrb.r_workarea = work_area;
2189 zrb.r_palette = zpalette;
2190 zrb.r_linesp = 0;
2191 zrb.r_for = TERM_WHITE;
2192 zrb.r_bac = 0;
2193 zrb.r_data = r_data;
2194 SWI(2, 0, SWI_ZapRedraw_ReadVduVars, 0, &zrb);
2195 }
2196
2197
2198
2199 /*
2200 | Set up the ZapRedrawBlock ready to redraw term 't'
2201 | (caches the r_data as part of the process)
2202 */
set_up_zrb(term_data * t)2203 static void set_up_zrb(term_data *t)
2204 {
2205 int fw, fh;
2206
2207 zrb.r_flags.value = 0;
2208
2209 /* Set font info up */
2210 fw = t->font->w;
2211 fh = t->font->h;
2212 SWI(4, 4, SWI_ZapRedraw_CachedCharSize, zrb.r_bpp, 0, fw, fh,
2213 NULL, NULL, &(zrb.r_cbpl), &(zrb.r_cbpc));
2214 zrb.r_caddr = (void *)(((int)t->font->bpp_n) - (t->font->f * zrb.r_cbpc));
2215
2216 zrb.r_charw = fw; /* Character size in pixels */
2217 zrb.r_charh = fh;
2218
2219 if (t->font == SYSTEM_FONT)
2220 zrb.r_flags.bits.double_height = screen_eig.y == 1;
2221 else
2222 zrb.r_flags.bits.double_height = 0;
2223
2224 make_r_data(t); /* Cache the r_data */
2225 }
2226
2227
2228
2229
2230
RO_redraw_window(window_redrawblock * rb,BOOL * more,term_data * t)2231 static void RO_redraw_window(window_redrawblock * rb, BOOL *more, term_data *t)
2232 {
2233 int cx, cy, cw, ch;
2234
2235 /* set GCOL for cursor colour */
2236 if (t->cursor.visible)
2237 {
2238 cw = zrb.r_charw << screen_eig.x;
2239 ch = -(zrb.r_charh << screen_eig.y);
2240 if (zrb.r_flags.bits.double_height)
2241 {
2242 ch *= 2;
2243 }
2244 cx = t->cursor.pos.x * cw;
2245 cy = t->cursor.pos.y * ch;
2246 cx += (rb->rect.min.x - rb->scroll.x);
2247 cy += (rb->rect.max.y - rb->scroll.y);
2248 cw -= (1 << screen_eig.x);
2249 ch += (1 << screen_eig.y);
2250 cy -= (1 << screen_eig.y);
2251 }
2252
2253 while (*more)
2254 {
2255 SWI(2, 0, SWI_ZapRedraw_GetRectangle, rb, &zrb);
2256 SWI(2, 0, SWI_ZapRedraw_RedrawArea, NULL, &zrb);
2257 if (t->cursor.visible)
2258 {
2259 ColourTrans_SetGCOL(cursor_rgb, 0, 0);
2260 GFX_Move(cx, cy);
2261 GFX_DrawBy(cw, 0);
2262 GFX_DrawBy(0, ch);
2263 GFX_DrawBy(-cw, 0);
2264 GFX_DrawBy(0, -ch);
2265 }
2266 Wimp_GetRectangle(rb, more);
2267 }
2268 }
2269
2270
2271
2272
2273
Hnd_Redraw(event_pollblock * pb,void * ref)2274 static BOOL Hnd_Redraw(event_pollblock * pb, void *ref)
2275 {
2276 term_data *t = (term_data *)ref;
2277 window_redrawblock rb;
2278 BOOL more;
2279
2280 rb.window = t->w;
2281 Wimp_RedrawWindow(&rb, &more);
2282
2283 set_up_zrb(t);
2284
2285 RO_redraw_window(&rb, &more, t);
2286
2287 return TRUE;
2288 }
2289
2290
2291
2292
2293
refresh_window(term_data * t)2294 static void refresh_window(term_data *t)
2295 {
2296 window_redrawblock rb;
2297 BOOL more;
2298 int fw, fh;
2299
2300 if ((t->changed_box.min.x >= t->changed_box.max.x) ||
2301 (t->changed_box.min.y >= t->changed_box.max.y))
2302 return;
2303
2304 set_up_zrb(t);
2305
2306 fw = zrb.r_charw << screen_eig.x;
2307 fh = -(zrb.r_charh << screen_eig.y);
2308 if (zrb.r_flags.bits.double_height)
2309 {
2310 fh *= 2;
2311 }
2312
2313 rb.window = t->w;
2314 rb.rect.min.x = fw * t->changed_box.min.x;
2315 rb.rect.max.x = fw * t->changed_box.max.x;
2316
2317 rb.rect.max.y = fh * t->changed_box.min.y;
2318 rb.rect.min.y = fh * t->changed_box.max.y;
2319
2320 Wimp_UpdateWindow(&rb, &more);
2321 RO_redraw_window(&rb, &more, t);
2322
2323 t->changed_box.min.x = t->changed_box.min.y = 255;
2324 t->changed_box.max.x = t->changed_box.max.y = 0;
2325 }
2326
2327
2328
refresh_windows(void)2329 static void refresh_windows(void)
2330 {
2331 int i;
2332 window_info info;
2333 for (i = 0; i < MAX_TERM_DATA; i++)
2334 {
2335 info.window = data[i].w;
2336 Wimp_GetWindowInfo(&info);
2337 if (info.block.flags.data.open)
2338 refresh_window(&(data[i]));
2339 }
2340 }
2341
2342
2343 /*
2344 | Set the size of a window.
2345 | If the window grows but has no scroll bars then it is re-sized to
2346 | the new extent. If it shrinks then it is resized regardless.
2347 |
2348 | If the window isn't open then it is opened behind the backwindow,
2349 | resized and then closed again... I /did/ have a reason for doing this
2350 | rather than simply recreating the window at the new size, but for the
2351 | life of me I can't remember what it was...
2352 */
set_window_size(window_handle w,int width,int height)2353 static void set_window_size(window_handle w, int width, int height)
2354 {
2355 window_state ws;
2356 int reclose;
2357 /*
2358 * int cw,ch;
2359 */
2360
2361 Wimp_GetWindowState(w, &ws);
2362 Window_SetExtent(w, 0, -height, width, 0);
2363
2364 reclose = !ws.flags.data.open;
2365 if (!(ws.flags.value & (0xf << 27)))
2366 {
2367 if (reclose)
2368 {
2369 ws.openblock.behind = -3;
2370 Wimp_OpenWindow(&(ws.openblock));
2371 }
2372 /* Removed - caused "pixel creep" :)
2373 * cw = ws.openblock.screenrect.max.x;
2374 * ch = ws.openblock.screenrect.max.y;
2375 * cw -= ws.openblock.screenrect.min.x;
2376 * ch -= ws.openblock.screenrect.min.y;
2377 * ws.openblock.screenrect.min.x -= ((width-cw)/2)-(1<<screen_eig.x);
2378 * ws.openblock.screenrect.min.y -= ((height-ch)/2)-(1<<screen_eig.y);
2379 */
2380 ws.openblock.screenrect.max.x = ws.openblock.screenrect.min.x + width;
2381 ws.openblock.screenrect.max.y = ws.openblock.screenrect.min.y + height;
2382 Wimp_OpenWindow(&(ws.openblock));
2383 if (reclose)
2384 {
2385 Wimp_CloseWindow(w);
2386 }
2387 }
2388 }
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404 /*
2405 | Change the size of a window to suit the font displayed in it
2406 */
resize_term_for_font(term_data * t)2407 static void resize_term_for_font(term_data *t)
2408 {
2409 int fw, fh;
2410 set_up_zrb(t);
2411
2412 fw = zrb.r_charw << screen_eig.x;
2413 fh = zrb.r_charh << screen_eig.y;
2414 if (zrb.r_flags.bits.double_height)
2415 {
2416 fh *= 2;
2417 }
2418
2419 /* Caulculate new size */
2420 fw *= 80;
2421 fh *= 24;
2422
2423 set_window_size(t->w, fw, fh);
2424 }
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
Hnd_Caret(event_pollblock * pb,void * ref)2444 static BOOL Hnd_Caret(event_pollblock * pb, void *ref)
2445 {
2446 if (ref)
2447 got_caret = 1;
2448 else
2449 got_caret = 0;
2450 return TRUE;
2451 }
2452
2453
2454
2455
2456 /*
2457 | Attach a (named) font to the specified term.
2458 | If 'font' is NULL then the system font is attached.
2459 | The bpp_n data is calculated if necessary
2460 | returns:
2461 | 1 => the font was attached OK
2462 | 0 => the system font was substituted
2463 */
attach_font_to_term(term_data * t,char * font)2464 static int attach_font_to_term(term_data *t, char *font)
2465 {
2466 if (t->font != SYSTEM_FONT)
2467 {
2468 lose_font(t->font);
2469 }
2470 if (font)
2471 {
2472 t->font = find_font(font);
2473 }
2474 if (!t->font)
2475 {
2476 t->font = SYSTEM_FONT;
2477 if (font)
2478 {
2479 Msgs_Report(1, "err.font_l", font);
2480 }
2481 }
2482 else
2483 {
2484 if (!t->font->bpp_n)
2485 {
2486 lose_font(t->font);
2487 t->font = SYSTEM_FONT;
2488 if (font)
2489 {
2490 Msgs_Report(1, "err.font_c", font);
2491 }
2492 }
2493 }
2494 resize_term_for_font(t);
2495 return !(t->font == SYSTEM_FONT);
2496 }
2497
2498
2499
2500
2501 /*--------------------------------------------------------------------------*/
2502
2503
2504
2505 /*
2506 | Create a menu of all the (probable!) fonts in the specified location
2507 | NB: Any file of type 'data' is considered a font.
2508 |
2509 | Subdirectories are recursively searched.
2510 |
2511 | 1.10 - Uses <variant>$FontPaths to get a (space separated) list of paths
2512 | to search. For each path name, the menu text will be the name and the
2513 | path searched will be <variant>$<name>$FontPath
2514 |
2515 | Eg. (for angband):
2516 | Angband$FontPaths Zap Angband
2517 | Angband$Zap$FontPath ZapFonts:
2518 | Angband$Angband$FontPath Angband:xtra.fonts.
2519 */
make_font_menu(void)2520 static void make_font_menu(void)
2521 {
2522 char *t;
2523 char buffer[260];
2524 char menu_buffer[260];
2525 int paths;
2526 int i;
2527 unsigned int max_width;
2528 const char *path[64]; /* pointers to path names */
2529 menu_item *mi;
2530
2531 font_menu = NULL;
2532
2533 /* Get the path (ie. dir) to look under */
2534 t = getenv(RISCOS_VARIANT "$FontPaths");
2535
2536 /* Hack: cope if the path isn't set */
2537 if (!t)
2538 {
2539 t = "";
2540 }
2541
2542 strcpy(buffer, t);
2543
2544 /*
2545 | Count how many paths there are, build an array of pointers to them
2546 | and terminate them in the buffer
2547 */
2548 paths = 1; /* including the system font fake path '<System>' */
2549 for (t = buffer; *t; t++)
2550 {
2551 if (*t == ' ')
2552 {
2553 *t = 0;
2554 }
2555 else
2556 {
2557 if (t == buffer || !t[-1])
2558 {
2559 path[paths] = t;
2560 paths++;
2561 }
2562 }
2563 }
2564
2565 /*
2566 | Create the menu
2567 */
2568 path[0] = SYSTEM_FONT->name;
2569
2570 font_menu = f_malloc(sizeof(menu_block) + paths * sizeof(menu_item));
2571 if (!font_menu)
2572 {
2573 core("Out of memory (building font menu)");
2574 }
2575 memset(font_menu, 0, sizeof(menu_block) + paths * sizeof(menu_item));
2576
2577 strncpy(font_menu->title, "Fonts", 12);
2578 font_menu->titlefore = 7;
2579 font_menu->titleback = 2;
2580 font_menu->workfore = 7;
2581 font_menu->workback = 0;
2582 font_menu->height = 44;
2583 font_menu->gap = 0;
2584 max_width = strlen(font_menu->title);
2585
2586 mi = (menu_item *) (font_menu + 1);
2587
2588 for (i = 0; i < paths; i++)
2589 {
2590 mi[i].submenu.value = -1;
2591 mi[i].iconflags.data.text = 1;
2592 mi[i].iconflags.data.filled = 1;
2593 mi[i].iconflags.data.foreground = 7;
2594 mi[i].iconflags.data.background = 0;
2595 strncpy(mi[i].icondata.text, path[i], 12);
2596 if (strlen(mi[i].icondata.text) > max_width)
2597 max_width = strlen(mi[i].icondata.text);
2598 }
2599 font_menu->width = (max_width + 2) * 16;
2600 mi[i - 1].menuflags.data.last = 1;
2601
2602 /*
2603 | Hack: add a dotted line after the system font entry if appropriate
2604 */
2605 if (paths > 1) mi[0].menuflags.data.dotted = 1;
2606
2607 /*
2608 | Iterate over the paths, building the appropriate submenus
2609 */
2610 for (i = 1; i < paths; i++)
2611 {
2612 menu_ptr sub_menu = NULL;
2613
2614 sprintf(menu_buffer, "%s$%s$FontPath", RISCOS_VARIANT, path[i]);
2615 t = getenv(menu_buffer);
2616 /* Hack: cope if the path isn't defined */
2617 if (!t)
2618 {
2619 t = "";
2620 }
2621
2622 /* Fudge so that the fontpath can be a path, not just a dir. */
2623 strcpy(menu_buffer, t);
2624 for (t = menu_buffer; *t > ' '; t++)
2625 ;
2626 if (t[-1] == '.')
2627 {
2628 t--;
2629 }
2630 *t = 0;
2631
2632 /* Build the menu. Don't bother if the path variable was empty */
2633 if (*menu_buffer)
2634 sub_menu = make_zfont_menu(menu_buffer);
2635
2636 if (!sub_menu)
2637 {
2638 mi[i].iconflags.data.shaded = 1;
2639 }
2640 else
2641 {
2642 mi[i].submenu.menu = sub_menu;
2643 /* Override the title of the 'root' sub-menu */
2644 strncpy(sub_menu->title, path[i], 12);
2645 /* Add the submenu to the main menu */
2646 }
2647 }
2648
2649 return;
2650 }
2651
2652 /* ----------------------------------------------- musus, xxxx-xx-xx ---
2653 * Create and set up the infobox.
2654 * --------------------------------------------------------------------- */
create_info_box(void)2655 static void create_info_box(void)
2656 {
2657 info_box = Window_Create("info", template_TITLEMIN);
2658 Icon_printf(info_box, 0, "%s %s", VARIANT, VERSION);
2659 Icon_SetText(info_box, 2, AUTHORS);
2660 Icon_SetText(info_box, 3, PORTERS);
2661 Icon_SetText(info_box, 7, PORTVERSION);
2662
2663 return;
2664 }
2665
2666 /*
2667 | Create the various menus
2668 */
init_menus(void)2669 static void init_menus(void)
2670 {
2671 char buffer1[256];
2672 char buffer2[32];
2673 char *o;
2674
2675 create_info_box(); /* For the Info> entries */
2676 make_font_menu(); /* Make the fonts menu */
2677
2678 Msgs_Lookup("menu.ibar:Info|>Save As|Full screen,Gamma correction,Sound,"
2679 "Windows|Save choices|Quit (& save)", buffer1, 256);
2680 ibar_menu = Menu_New(VARIANT, buffer1);
2681 if (!ibar_menu) core("Can't create Iconbar menu!");
2682
2683 Msgs_Lookup("menu.term:Info|>Save As|Font,Windows", buffer1, 256);
2684 term_menu = Menu_New(VARIANT, buffer1);
2685 if (!term_menu) core("Can't create Term menu!");
2686
2687 #ifndef OLD_TERM_MENU
2688 o = buffer1;
2689 o += sprintf(buffer1, "%s|", VARIANT);
2690 o += sprintf(o, "%s,%s,%s|", angband_term_name[1], angband_term_name[2],
2691 angband_term_name[3]);
2692 sprintf(o, "%s,%s,%s,%s", angband_term_name[4], angband_term_name[5],
2693 angband_term_name[6], angband_term_name[7]);
2694 #else
2695 Msgs_printf(buffer1, "menu.windows:%s|Term-1 (Mirror),Term-2 (Recall),"
2696 "Term-3 (Choice)|Term-4,Term-5,Term-6,Term-7", VARIANT);
2697 #endif
2698 Msgs_Lookup("menu.winT:Windows", buffer2, 32);
2699 wind_menu = Menu_New(buffer2, buffer1);
2700 if (!wind_menu)
2701 {
2702 core("Can't create Windows menu!");
2703 }
2704
2705 /* Now attach the various submenus to where they belong */
2706 Menu_AddSubMenu(ibar_menu, IBAR_MENU_INFO, (menu_ptr) info_box);
2707 Menu_AddSubMenu(ibar_menu, IBAR_MENU_GAMMA, (menu_ptr) gamma_win);
2708 Menu_AddSubMenu(ibar_menu, IBAR_MENU_SOUND, (menu_ptr) sound_win);
2709 Menu_AddSubMenu(ibar_menu, IBAR_MENU_WINDOWS, (menu_ptr) wind_menu);
2710 Menu_AddSubMenu(term_menu, TERM_MENU_INFO, (menu_ptr) info_box);
2711 Menu_AddSubMenu(term_menu, TERM_MENU_WINDOWS, wind_menu);
2712
2713 /* Add the savebox */
2714 Menu_Warn(ibar_menu, IBAR_MENU_SAVE, TRUE, Hnd_SaveWarning, NULL);
2715 Menu_Warn(term_menu, TERM_MENU_SAVE, TRUE, Hnd_SaveWarning, NULL);
2716
2717 if (font_menu)
2718 /* add the submenu */
2719 Menu_AddSubMenu(term_menu, TERM_MENU_FONT, font_menu);
2720 else
2721 /* If the font menu is buggered, shade its entry */
2722 /* unticked, shaded */
2723 Menu_SetFlags(term_menu, TERM_MENU_FONT, FALSE, TRUE);
2724 }
2725
2726
2727
2728
grab_caret(void)2729 static void grab_caret(void)
2730 {
2731 caret_block cb;
2732 cb.window = data[0].w;
2733 cb.icon = -1;
2734 cb.height = 1 << 25; /* Invisible */
2735 Wimp_SetCaretPosition(&cb);
2736 }
2737
2738
2739
2740
2741 /*
2742 | (Recursively) clear all ticks from the specified menu
2743 */
clear_all_menu_ticks(menu_ptr mp)2744 static void clear_all_menu_ticks(menu_ptr mp)
2745 {
2746 menu_item *mi = (menu_item *) (mp + 1);
2747
2748 do
2749 {
2750 if (mi->menuflags.data.ticked)
2751 mi->menuflags.data.ticked = 0;
2752 if (mi->submenu.value != -1)
2753 clear_all_menu_ticks(mi->submenu.menu);
2754 mi++;
2755 }
2756 while (mi[-1].menuflags.data.last != 1);
2757 }
2758
2759
2760
2761
2762
2763
2764 /*
2765 | Set the font menu's ticks to match the specifed font name.
2766 |
2767 | fm is the (sub) menu to scan down (recursing into it's submenus (if any))
2768 | fn is the font name to match
2769 | prefix is the menu text to be prepended to the menu entries due to
2770 | previous menus (eg. "08x16" will cause fn="08x16.fred" to match menu
2771 | entry "fred".
2772 |
2773 | NB: recursive.
2774 |
2775 */
2776
set_font_menu_ticks(menu_ptr fm,char * fn,const char * prefix)2777 static void set_font_menu_ticks(menu_ptr fm, char *fn, const char *prefix)
2778 {
2779 char buffer[260];
2780 char *b_leaf; /* -> menu 'leaf' text in buffer */
2781 int pl; /* prefix string length */
2782 menu_item *mi = (menu_item *) (fm + 1);
2783
2784 strcpy(buffer, prefix);
2785 pl = strlen(buffer);
2786 b_leaf = buffer + pl;
2787
2788 do
2789 {
2790 /* Check for (substring) match */
2791 strncpy(b_leaf, mi->icondata.text, 12);
2792
2793 /* Is it a sub-menu? */
2794 if (mi->submenu.value == -1)
2795 {
2796 /* No - must be an exact match */
2797 mi->menuflags.data.ticked = !strcmp(buffer, fn);
2798 }
2799 else
2800 {
2801 /* Yes - must be a partial match (with a dot on :) */
2802 strcat(b_leaf, ".");
2803 mi->menuflags.data.ticked =
2804 !strncmp(buffer, fn, pl + strlen(b_leaf));
2805 if (mi->menuflags.data.ticked)
2806 set_font_menu_ticks(mi->submenu.menu, fn, buffer);
2807 else
2808 clear_all_menu_ticks(mi->submenu.menu);
2809 }
2810
2811 /* Next item */
2812 mi++;
2813 }
2814 while (mi[-1].menuflags.data.last != 1); /* Until finished */
2815 }
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827 /*
2828 | Set ticks, etc. in the term_menu to reflect the current state of the
2829 | term 't'
2830 */
set_up_term_menu(term_data * t)2831 static void set_up_term_menu(term_data *t)
2832 {
2833 int i;
2834 menu_ptr mp;
2835 menu_item *mi;
2836 window_state ws;
2837
2838 /* First of all, set up menu title to be the term's title */
2839 strncpy(term_menu->title, t->name, 12);
2840
2841 /* Now set the ticks in the Windows> submenu (cuz it's easy) */
2842 mp = wind_menu; /* Windows submenu */
2843 mi = (menu_item *) (mp + 1); /* First entry */
2844 for (i = 0; i < MAX_TERM_DATA; i++)
2845 {
2846 Wimp_GetWindowState(data[i].w, &ws);
2847 mi[i].menuflags.data.ticked = ws.flags.data.open;
2848 }
2849
2850 /*
2851 | Now, the tricky bit: find out which font is selected in this
2852 | term and tick it in the menu. Untick all the rest.
2853 */
2854 set_font_menu_ticks(font_menu, t->font->name, "");
2855
2856 /* Shade the 'Save>' entry if saving isn't possible (yet) */
2857 if (game_in_progress && character_generated)
2858 Menu_SetFlags(term_menu, TERM_MENU_SAVE, 0, PDEADCHK);
2859 else
2860 Menu_SetFlags(term_menu, TERM_MENU_SAVE, 0, TRUE);
2861
2862 }
2863
2864
2865
2866 /*
2867 | Generic 'click' handler for windows - turns a drag on the window
2868 | into a move-window style drag.
2869 */
Hnd_Click(event_pollblock * pb,void * ref)2870 static BOOL Hnd_Click(event_pollblock * pb, void *ref)
2871 {
2872 if (pb->data.mouse.button.data.dragselect ||
2873 pb->data.mouse.button.data.dragadjust)
2874 {
2875 drag_block b;
2876 b.window = pb->data.mouse.window;
2877 b.screenrect.min.x = b.screenrect.min.y = 0;
2878 b.screenrect.max.x = screen_size.x;
2879 b.screenrect.max.y = screen_size.y;
2880 b.type = drag_MOVEWINDOW;
2881 Wimp_DragBox(&b);
2882 }
2883
2884 return TRUE;
2885 }
2886
2887
2888
2889 /*
2890 | Handle a click on a Term window.
2891 */
Hnd_TermClick(event_pollblock * pb,void * ref)2892 static BOOL Hnd_TermClick(event_pollblock * pb, void *ref)
2893 {
2894 term_data *t = (term_data *)ref;
2895
2896 if (pb->data.mouse.button.data.menu)
2897 {
2898 menu_term = t;
2899 set_up_term_menu(t);
2900 Menu_Show(term_menu, pb->data.mouse.pos.x - 32,
2901 pb->data.mouse.pos.y + 32);
2902 }
2903 else
2904 {
2905 grab_caret();
2906 Hnd_Click(pb, ref);
2907 }
2908
2909 return TRUE;
2910 }
2911
2912 #endif /* FULLSCREEN_ONLY */
2913
2914
2915
mark_ood(term_data * t,int minx,int miny,int maxx,int maxy)2916 static void mark_ood(term_data *t, int minx, int miny, int maxx, int maxy)
2917 {
2918 if (t->changed_box.min.x > minx)
2919 t->changed_box.min.x = minx;
2920 if (t->changed_box.max.x < maxx)
2921 t->changed_box.max.x = maxx;
2922 if (t->changed_box.min.y > miny)
2923 t->changed_box.min.y = miny;
2924 if (t->changed_box.max.y < maxy)
2925 t->changed_box.max.y = maxy;
2926 }
2927
2928
2929 #ifndef FULLSCREEN_ONLY
2930
2931 /* Check for an event (ie. key press) */
Term_xtra_acn_check(void)2932 static errr Term_xtra_acn_check(void)
2933 {
2934 static int last_poll = 0;
2935 int curr_time;
2936 int bh, bl;
2937
2938 /*
2939 | Only poll the wimp if there's something in the keyboard buffer
2940 | or every 10cs
2941 */
2942
2943 /* Check the kbd buffer */
2944 SWI(3, 3, SWI_OS_Byte, 128, 255, 0, /**/ NULL, &bl, &bh);
2945 bl = (bl & 0xff) + (bh << 8);
2946
2947 /* Check how long it is since we last polled */
2948 curr_time = Time_Monotonic();
2949
2950 if ((bl > 0 && got_caret) || ((curr_time - last_poll) > 9))
2951 {
2952 last_poll = curr_time;
2953 Stop_Hourglass;
2954 Event_Poll();
2955 Start_Hourglass;
2956 }
2957
2958 /*
2959 | This allows the user to interrupt the borg.
2960 */
2961 if (key_pressed) return key_pressed = 0;
2962
2963 return 1;
2964 }
2965
2966
2967 /*
2968 | Wait for an event (ie. keypress)
2969 | Note that we idle poll once a second to allow us to implement the
2970 | alarm system.
2971 */
Term_xtra_acn_event(void)2972 static errr Term_xtra_acn_event(void)
2973 {
2974 Stop_Hourglass;
2975
2976 while (!key_pressed && !fullscreen_font)
2977 {
2978 Event_PollIdle(100);
2979 }
2980 Start_Hourglass;
2981
2982 return key_pressed = 0;
2983 }
2984
2985
2986
2987 /* React to changes (eg. palette change) */
Term_xtra_acn_react(void)2988 static errr Term_xtra_acn_react(void)
2989 {
2990 int c;
2991
2992 cache_palette();
2993
2994 /* Mark the entirety of each window as out of date */
2995 for (c = 0; c < MAX_TERM_DATA; c++)
2996 mark_ood(&data[c], 0, 0, 80, 24);
2997
2998 /* Force a redraw of the windows */
2999 refresh_windows();
3000
3001 /* Success */
3002 return 0;
3003 }
3004
3005
3006
3007 /* Do various things to a term */
Term_xtra_acn(int n,int v)3008 static errr Term_xtra_acn(int n, int v)
3009 {
3010 term_data *t = (term_data *)Term;
3011
3012 switch (n)
3013 {
3014 case TERM_XTRA_EVENT: /* Wait/check for an event */
3015 if (v)
3016 return Term_xtra_acn_event();
3017 else
3018 return Term_xtra_acn_check();
3019
3020 case TERM_XTRA_BORED: /* Bored */
3021 return Term_xtra_acn_check();
3022
3023 case TERM_XTRA_FLUSH: /* Flush input */
3024 if (got_caret)
3025 {
3026 /* 1.21 - Hack: wait until no keys are pressed */
3027 if (hack_flush)
3028 for (v = 0; v != 0xff;)
3029 SWI(1, 2, SWI_OS_Byte, 122, 0, &v);
3030 SWI(3, 0, SWI_OS_Byte, 21, 0, 0); /* Flush Kbd buffer */
3031 }
3032 return 0;
3033
3034 case TERM_XTRA_FRESH: /* Flush output */
3035 refresh_window(t);
3036 return 0;
3037
3038 case TERM_XTRA_FROSH: /* Ensure line 'v' is plotted */
3039 /* Doesn't do anything */
3040 return 0;
3041
3042 case TERM_XTRA_SHAPE: /* Set cursor visibility */
3043 t->cursor.visible = v ? TRUE : FALSE;
3044 mark_ood(t, t->cursor.pos.x, t->cursor.pos.y,
3045 t->cursor.pos.x + 1, t->cursor.pos.y + 1);
3046 refresh_window(t); /* needed? */
3047 return 0;
3048
3049 case TERM_XTRA_NOISE: /* Make a beep */
3050 Sound_SysBeep();
3051 return 0;
3052
3053 case TERM_XTRA_REACT: /* React to, eg. palette changes */
3054 return Term_xtra_acn_react();
3055
3056 case TERM_XTRA_DELAY: /* Delay for 'v' ms */
3057 if (v > 0)
3058 {
3059 unsigned int start = Time_Monotonic();
3060 v = (v + 5) / 10; /* Round to nearest cs */
3061 GFX_Wait();
3062 while ((Time_Monotonic() - start) < v)
3063 ;
3064 }
3065 return 0;
3066
3067 case TERM_XTRA_SOUND: /* Play a sound :) */
3068 if (enable_sound)
3069 {
3070 play_sound(v);
3071 }
3072 return 0;
3073
3074 default:
3075 return 1; /* Unsupported */
3076 }
3077 }
3078
3079
3080
3081 /* Move (but don't necessarily display) the cursor */
Term_curs_acn(int x,int y)3082 static errr Term_curs_acn(int x, int y)
3083 {
3084 term_data *t = (term_data *)Term;
3085
3086 if (t->cursor.visible)
3087 mark_ood(t, t->cursor.pos.x, t->cursor.pos.y,
3088 t->cursor.pos.x + 1, t->cursor.pos.y + 1);
3089
3090 t->cursor.pos.x = x;
3091 t->cursor.pos.y = y;
3092
3093 if (t->cursor.visible)
3094 mark_ood(t, t->cursor.pos.x, t->cursor.pos.y,
3095 t->cursor.pos.x + 1, t->cursor.pos.y + 1);
3096
3097 return 0;
3098 }
3099
3100
3101
3102 /*
3103 | NB: these two are very simple since we use the Term's contents
3104 | directly to generate the r_data for ZapRedraw.
3105 */
3106
3107 /* Erase 'n' characters at (x,y) */
Term_wipe_acn(int x,int y,int n)3108 static errr Term_wipe_acn(int x, int y, int n)
3109 {
3110 mark_ood((term_data *)Term, x, y, x + n, y + 1);
3111 return 0;
3112 }
3113
3114 /* Write 'n' characters from 's' with attr 'a' at (x,y) */
Term_text_acn(int x,int y,int n,byte a,cptr s)3115 static errr Term_text_acn(int x, int y, int n, byte a, cptr s)
3116 {
3117 mark_ood((term_data *)Term, x, y, x + n, y + 1);
3118 return 0;
3119 }
3120
3121 #endif /* FULLSCREEN_ONLY */
3122
3123
3124 /* Initialise one of our terms */
Term_init_acn(term * t)3125 static void Term_init_acn(term *t)
3126 {
3127 term_data *term = (term_data *)t;
3128
3129 /* Ludicrous changed box settings :) */
3130 term->changed_box.min.x = 256;
3131 term->changed_box.min.y = 256;
3132 term->changed_box.max.x = 0;
3133 term->changed_box.max.y = 0;
3134 }
3135
3136
3137
term_data_link(term_data * td,int k)3138 static void term_data_link(term_data *td, int k)
3139 {
3140 term *t = &(td->t);
3141
3142 /* Initialise the term */
3143 term_init(t, 80, 24, k);
3144
3145 /* Set flags and hooks */
3146 t->attr_blank = TERM_DARK;
3147 t->char_blank = ' ';
3148
3149 /* Experiment (FS mode requires them) */
3150 t->always_text = TRUE;
3151 t->never_frosh = TRUE;
3152 /* Experiment (FS mode requires them) */
3153
3154 #ifdef FULLSCREEN_ONLY
3155 t->wipe_hook = Term_wipe_acnFS;
3156 t->xtra_hook = Term_xtra_acnFS;
3157 t->curs_hook = Term_curs_acnFS;
3158 t->text_hook = Term_text_acnFS;
3159 #else
3160 t->init_hook = Term_init_acn;
3161 t->xtra_hook = Term_xtra_acn;
3162 t->wipe_hook = Term_wipe_acn;
3163 t->curs_hook = Term_curs_acn;
3164 t->text_hook = Term_text_acn;
3165 t->user_hook = Term_user_acn;
3166 #endif /* FULLSCREEN_ONLY */
3167
3168 t->data = td;
3169
3170 Term_activate(t);
3171 }
3172
3173
3174 #ifndef FULLSCREEN_ONLY
3175
3176 /* Open default windows (ie. as set in choices) at the appropriate sizes */
show_windows(void)3177 static void show_windows(void)
3178 {
3179 int i;
3180 for (i = MAX_TERM_DATA; i-- > 0;)
3181 {
3182 if (!data[i].unopened)
3183 {
3184 if (data[i].def_open)
3185 Window_Show(data[i].w, open_WHEREVER);
3186 }
3187 else
3188 {
3189 if (data[i].def_open)
3190 {
3191 window_openblock ob;
3192 ob.window = data[i].w;
3193 ob.screenrect = data[i].def_pos;
3194 ob.scroll = data[i].def_scroll;
3195 ob.behind = -1;
3196 Wimp_OpenWindow(&ob);
3197 data[i].unopened = 0;
3198 }
3199 }
3200 }
3201 }
3202
3203
3204 /*
3205 | 'ref' is used to indicate whether this close is being forced by some other
3206 | part of the code (eg. the Windows> submenu code). This is used to modify
3207 | the 'adjust doesn't close other terms' behavior.
3208 */
3209
Hnd_MainClose(event_pollblock * pb,void * ref)3210 static BOOL Hnd_MainClose(event_pollblock * pb, void *ref)
3211 {
3212 int i;
3213 window_state ws;
3214 mouse_block mb;
3215
3216 /* New in 1.08: don't close other Terms if closed with adjust */
3217 Wimp_GetPointerInfo(&mb);
3218 if (ref || mb.button.data.adjust)
3219 {
3220 Wimp_CloseWindow(data[0].w);
3221 }
3222 else
3223 {
3224 /* Close all the terms, but mark the open ones as 'def_open' */
3225 for (i = 0; i < MAX_TERM_DATA; i++)
3226 {
3227 Wimp_GetWindowState(data[i].w, &ws);
3228 if (!ws.flags.data.open)
3229 {
3230 data[i].def_open = 0;
3231 }
3232 else
3233 {
3234 Wimp_CloseWindow(data[i].w);
3235 data[i].def_open = 1;
3236 }
3237 }
3238 }
3239
3240 return TRUE;
3241 }
3242
3243
Hnd_PaletteChange(event_pollblock * pb,void * ref)3244 static BOOL Hnd_PaletteChange(event_pollblock * pb, void *ref)
3245 {
3246 cache_palette();
3247 return TRUE;
3248 }
3249
3250
3251
Hnd_ModeChange(event_pollblock * pb,void * ref)3252 static BOOL Hnd_ModeChange(event_pollblock * pb, void *ref)
3253 {
3254 int i;
3255 Screen_CacheModeInfo();
3256 set_up_zrb_for_mode(); /* (re)set up the redraw block */
3257 cache_palette(); /* (re)cache the palette */
3258 cache_fonts(); /* (re)cache the fonts */
3259 /* Enforce sizes (eg. if screen_eig.y has changed) */
3260 for (i = 0; i < MAX_TERM_DATA; i++)
3261 resize_term_for_font(&(data[i]));
3262 return TRUE;
3263 }
3264
3265
3266
3267
Hnd_Keypress(event_pollblock * pb,void * ref)3268 static BOOL Hnd_Keypress(event_pollblock * pb, void *ref)
3269 {
3270 static const char hex[] = "0123456789ABCDEF";
3271 int c = pb->data.key.code;
3272 /* Check whether this key was pressed in Term 0 */
3273 if (pb->data.key.caret.window == data[0].w)
3274 {
3275 switch (c)
3276 {
3277 case keycode_F12:
3278 case keycode_SHIFT_F12:
3279 case keycode_CTRL_F12:
3280 case keycode_CTRL_SHIFT_F12:
3281 /* Never intercept these */
3282 break;
3283
3284 case 27: /* handle escape specially */
3285 if (Kbd_KeyDown(inkey_CTRL))
3286 {
3287 ack_alarm();
3288 return TRUE;
3289 }
3290
3291 /* Send everything else onto the Term package */
3292 default:
3293 /* Take care of "special" keypresses */
3294 switch (c)
3295 {
3296 case keycode_TAB:
3297 {
3298 c = '\t';
3299 break;
3300 }
3301
3302 case keycode_PAGEUP:
3303 {
3304 c = '9';
3305 break;
3306 }
3307
3308 case keycode_PAGEDOWN:
3309 {
3310 c = '3';
3311 break;
3312 }
3313
3314 case keycode_COPY:
3315 {
3316 c = '1';
3317 break;
3318 }
3319
3320 case keycode_HOME:
3321 {
3322 c = '7';
3323 break;
3324 }
3325 }
3326 /* Pass to the angband engine */
3327 /* Allow shift & ctrl to modify the keypad keys */
3328 if (c >= '0' && c <= '9')
3329 {
3330 kbd_modifiers m = Kbd_GetModifiers(FALSE);
3331 if (m.shift)
3332 {
3333 c |= 0x800;
3334 }
3335 if (m.ctrl)
3336 {
3337 c |= 0x400;
3338 }
3339 /* Could maybe add ALT as 0x1000 ??? */
3340 }
3341
3342 /* Keys >255 have to be send as escape sequences (31=escape) */
3343 if (c > 255 || c == 31)
3344 {
3345 Term_keypress(31);
3346 Term_keypress(hex[(c & 0xf00) >> 8]);
3347 Term_keypress(hex[(c & 0x0f0) >> 4]);
3348 Term_keypress(hex[(c & 0x00f)]);
3349 c = 13;
3350 }
3351 Term_keypress(c);
3352 key_pressed = 1;
3353 /*if ( c==27 ) { escape_pressed = 1; } */
3354 return TRUE;
3355 }
3356 }
3357
3358 Wimp_ProcessKey(c);
3359 return TRUE;
3360 }
3361
3362
3363 /*--------------------------------------------------------------------------*/
3364 /* Gamma correction window stuff */
3365 /*--------------------------------------------------------------------------*/
3366
redraw_gamma(window_redrawblock * rb,BOOL * more)3367 static void redraw_gamma(window_redrawblock * rb, BOOL *more)
3368 {
3369 int i, y, x, h, w;
3370 int bx, by;
3371 int dither;
3372
3373 bx = Coord_XToScreen(GC_XOFF, (convert_block *) & (rb->rect));
3374 by = Coord_YToScreen(GC_YOFF, (convert_block *) & (rb->rect));
3375
3376 h = GC_HEIGHT / 4;
3377 w = GC_WIDTH / 16;
3378
3379 x = bx;
3380
3381 while (*more)
3382 {
3383 for (i = 0; i < 16; i++)
3384 {
3385 y = by;
3386 for (dither = 0; dither < 2; dither++)
3387 {
3388 /* Solid block: */
3389 ColourTrans_SetGCOL(palette[i], dither << 8, 0);
3390 GFX_RectangleFill(x, y, w, -h);
3391 y -= h;
3392 /* Dot on black: */
3393 ColourTrans_SetGCOL(palette[0], dither << 8, 0);
3394 GFX_RectangleFill(x, y, w, -h);
3395 ColourTrans_SetGCOL(palette[i], dither << 8, 0);
3396 GFX_RectangleFill(x + (w / 2) - 2, y - (h / 2), 2, 2);
3397 y -= h;
3398 }
3399 x += w;
3400 }
3401 Wimp_GetRectangle(rb, more);
3402 }
3403 }
3404
3405
update_gamma(void)3406 static void update_gamma(void)
3407 {
3408 window_redrawblock rb;
3409 BOOL more;
3410
3411 rb.window = gamma_win;
3412 rb.rect.min.x = GC_XOFF;
3413 rb.rect.min.y = GC_YOFF - GC_HEIGHT;
3414 rb.rect.max.y = GC_XOFF + GC_WIDTH + screen_delta.x;
3415 rb.rect.max.y = GC_YOFF + screen_delta.y;
3416
3417 Wimp_UpdateWindow(&rb, &more);
3418 if (more)
3419 {
3420 redraw_gamma(&rb, &more);
3421 }
3422 }
3423
3424
3425
Hnd_RedrawGamma(event_pollblock * pb,void * ref)3426 static BOOL Hnd_RedrawGamma(event_pollblock * pb, void *ref)
3427 {
3428 window_redrawblock rb;
3429 BOOL more;
3430
3431 rb.window = pb->data.openblock.window;
3432 Wimp_RedrawWindow(&rb, &more);
3433 if (more)
3434 {
3435 redraw_gamma(&rb, &more);
3436 }
3437
3438 return TRUE;
3439 }
3440
3441
Hnd_GammaClick(event_pollblock * pb,void * ref)3442 static BOOL Hnd_GammaClick(event_pollblock * pb, void *ref)
3443 {
3444 int up = (ref == 0);
3445
3446 if (up)
3447 {
3448 if (gamma < 9.0)
3449 {
3450 gamma += 0.05;
3451 Icon_SetDouble(gamma_win, 0, gamma, 2);
3452 Term_xtra_acn_react();
3453 update_gamma();
3454 }
3455 }
3456 else
3457 {
3458 if (gamma > 0.05)
3459 {
3460 gamma -= 0.05;
3461 Icon_SetDouble(gamma_win, GAMMA_ICN, gamma, 2);
3462 Term_xtra_acn_react();
3463 update_gamma();
3464 }
3465 }
3466
3467 /* Hack: if the user menu is active then force it to redraw */
3468 if (user_menu_active)
3469 {
3470 Term_keypress(18);
3471 key_pressed = 1;
3472 }
3473
3474 return TRUE;
3475 }
3476
3477 /*
3478 | Reflect the current options in the gamma window
3479 */
set_gamma_window_state(void)3480 static void set_gamma_window_state(void)
3481 {
3482 if (minimise_memory) return;
3483
3484 Icon_SetDouble(gamma_win, 0, gamma, 2);
3485 }
3486
3487
init_gamma_window(void)3488 static void init_gamma_window(void)
3489 {
3490 if (minimise_memory) return;
3491
3492 Template_UseSpriteArea(resource_sprites);
3493 gamma_win = Window_Create("gamma", template_TITLEMIN);
3494 Template_UseSpriteArea(NULL);
3495 Event_Claim(event_REDRAW, gamma_win, event_ANY, Hnd_RedrawGamma, 0);
3496 Event_Claim(event_CLICK, gamma_win, GAMMA_DOWN, Hnd_GammaClick, (void *)1);
3497 Event_Claim(event_CLICK, gamma_win, GAMMA_UP, Hnd_GammaClick, (void *)0);
3498 set_gamma_window_state();
3499 }
3500
3501
3502 /*--------------------------------------------------------------------------*/
3503 /* Sound options window stuff */
3504 /*--------------------------------------------------------------------------*/
3505
3506 static slider_info volume_slider;
3507
3508
3509 /*
3510 | Reflect the current sound config in the sound options window
3511 */
set_sound_window_state(void)3512 static void set_sound_window_state(void)
3513 {
3514 if (minimise_memory) return;
3515
3516 Icon_SetSelect(sound_win, SND_ENABLE, enable_sound);
3517 Slider_SetValue(&volume_slider, sound_volume, NULL, NULL);
3518
3519 if (sound_volume > 127)
3520 volume_slider.colour.foreground = colour_RED;
3521 else
3522 volume_slider.colour.foreground = colour_GREEN;
3523 }
3524
3525
3526
3527 /*
3528 | The sound slider has been dragged, so update the sound volume setting
3529 */
update_volume_from_slider(slider_info * si,void * ref)3530 static int update_volume_from_slider(slider_info *si, void *ref)
3531 {
3532 sound_volume = Slider_ReadValue(si);
3533
3534 if (sound_volume > 127)
3535 volume_slider.colour.foreground = colour_RED;
3536 else
3537 volume_slider.colour.foreground = colour_GREEN;
3538
3539 return 0;
3540 }
3541
3542
3543 /*
3544 | Handle redraw events for the sound options window
3545 */
Hnd_RedrawSnd(event_pollblock * pb,void * ref)3546 static BOOL Hnd_RedrawSnd(event_pollblock * pb, void *ref)
3547 {
3548 window_redrawblock redraw;
3549 BOOL more;
3550
3551 redraw.window = pb->data.openblock.window;
3552 Wimp_RedrawWindow(&redraw, &more);
3553
3554 while (more)
3555 {
3556 Slider_Redraw(((slider_info *) ref), &redraw.cliprect);
3557 Wimp_GetRectangle(&redraw, &more);
3558 }
3559 return (TRUE);
3560 }
3561
3562
3563 /*
3564 | Handle clicks on the sound options window
3565 */
Hnd_SndClick(event_pollblock * pb,void * ref)3566 static BOOL Hnd_SndClick(event_pollblock * pb, void *ref)
3567 {
3568 int icn = pb->data.mouse.icon;
3569 int adj = pb->data.mouse.button.data.adjust;
3570 slider_info *si = (slider_info *) ref;
3571
3572 switch (icn)
3573 {
3574 /* Bump arrows for the slider: */
3575 case SND_VOL_DOWN:
3576 adj = !adj;
3577
3578 case SND_VOL_UP:
3579 adj = adj ? -1 : 1;
3580 sound_volume += adj;
3581 if (sound_volume < SOUND_VOL_MIN)
3582 {
3583 sound_volume = SOUND_VOL_MIN;
3584 }
3585 if (sound_volume > SOUND_VOL_MAX)
3586 {
3587 sound_volume = SOUND_VOL_MAX;
3588 }
3589 set_sound_window_state();
3590 break;
3591
3592 /* The slider itself */
3593 case SND_VOL_SLIDER:
3594 Icon_ForceRedraw(sound_win, SND_VOL_SLIDER);
3595 Slider_Drag(si, NULL, NULL, NULL);
3596 break;
3597
3598 /* The enable/disable icon */
3599 case SND_ENABLE:
3600 enable_sound = !enable_sound;
3601 Icon_SetSelect(sound_win, SND_ENABLE, enable_sound);
3602 if (enable_sound)
3603 {
3604 initialise_sound();
3605 }
3606 break;
3607 }
3608
3609 /* Hack: if the user menu is active then force it to redraw */
3610 if (user_menu_active)
3611 {
3612 Term_keypress(18);
3613 key_pressed = 1;
3614 }
3615
3616 return TRUE;
3617 }
3618
3619
3620
3621 /*
3622 | Set the sound options window up, ready to rock :)
3623 */
init_sound_window(void)3624 static void init_sound_window(void)
3625 {
3626 Template_UseSpriteArea(resource_sprites);
3627 sound_win = Window_Create("sound", template_TITLEMIN);
3628 Template_UseSpriteArea(NULL);
3629
3630 Event_Claim(event_REDRAW, sound_win, event_ANY, Hnd_RedrawSnd,
3631 (void *)&volume_slider);
3632 Event_Claim(event_CLICK, sound_win, event_ANY, Hnd_SndClick,
3633 (void *)&volume_slider);
3634
3635 /* Set up the slider info */
3636 volume_slider.window = sound_win;
3637 volume_slider.icon = SND_VOL_SLIDER;
3638 volume_slider.limits.min = SOUND_VOL_MIN;
3639 volume_slider.limits.max = SOUND_VOL_MAX;
3640 volume_slider.colour.foreground = colour_GREEN;
3641 volume_slider.colour.background = colour_WHITE;
3642 volume_slider.border.x = 8;
3643 volume_slider.border.y = 8;
3644 volume_slider.update = update_volume_from_slider;
3645
3646 set_sound_window_state();
3647 }
3648
3649
3650
3651
3652
3653 /*--------------------------------------------------------------------------*/
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665 /*
3666 | A font has been selected.
3667 | At this point, menu_term is a pointer to the term for which the
3668 | menu was opened.
3669 */
handle_font_selection(int * s)3670 static void handle_font_selection(int *s)
3671 {
3672 char name[260];
3673 os_error *e;
3674 char *r;
3675 menu_ptr mp = font_menu;
3676 int *mis;
3677
3678 /* Follow the >s to the entry specified */
3679 for (mis = s; *mis != -1; mis++)
3680 mp = ((menu_item *) (mp + 1))[*mis].submenu.menu;
3681
3682 /*
3683 | Now, check to see if we've hit a leaf entry.
3684 | NB: If the entry isn't a leaf entry then the first entry in its submenu
3685 | is used instead
3686 */
3687 if (((int)mp) != -1)
3688 {
3689 mis[0] = 0;
3690 mis[1] = -1;
3691 mp = ((menu_item *) (mp + 1))[0].submenu.menu;
3692 }
3693
3694 if (((int)mp) != -1)
3695 return;
3696
3697 e = Wimp_DecodeMenu(font_menu, s, name);
3698 if (e)
3699 {
3700 plog(e->errmess);
3701 return;
3702 }
3703
3704 /* Make sure that the string is NULL terminated */
3705 for (r = name; *r >= ' '; r++)
3706 ;
3707 *r = 0;
3708
3709 attach_font_to_term(menu_term, name);
3710 mark_ood(menu_term, 0, 0, 80, 24);
3711 refresh_window(menu_term);
3712 }
3713
3714
3715 #endif /* FULLSCREEN_ONLY */
3716
3717
3718
3719
load_choices(void)3720 static void load_choices(void)
3721 {
3722 FILE *fp = NULL;
3723 char *cf;
3724 int i;
3725 char buffer[260];
3726
3727 cf = find_choices(FALSE);
3728 if (*cf)
3729 fp = fopen(cf, "r");
3730
3731 /* Implement default choices */
3732 data[0].def_open = 1;
3733 data[0].unopened = 1; /* ie. force def_pos */
3734 data[0].def_pos.min.x = (screen_size.x - 1280) / 2;
3735 data[0].def_pos.max.x = (screen_size.x + 1280) / 2;
3736 data[0].def_pos.min.y = (screen_size.y - 768) / 2 - 32;
3737 data[0].def_pos.max.y = (screen_size.y + 768) / 2 - 32;
3738 data[0].def_scroll.x = data[0].def_scroll.y = 0;
3739 for (i = 1; i < MAX_TERM_DATA; i++)
3740 {
3741 data[i].def_open = 0;
3742 data[i].unopened = 1; /* ie. force def_pos */
3743 data[i].def_pos.min.x = (screen_size.x - 1280) / 2;
3744 data[i].def_pos.max.x = (screen_size.x + 1280) / 2;
3745 data[i].def_pos.min.y = (screen_size.y - 768) / 2;
3746 data[i].def_pos.max.y = (screen_size.y + 768) / 2;
3747 data[i].def_scroll.x = data[i].def_scroll.y = 0;
3748 }
3749
3750 if (fp)
3751 {
3752 const char *t_;
3753 char *o_;
3754
3755 if (!fgets(buffer, sizeof(buffer), fp))
3756 {
3757 fclose(fp);
3758 return;
3759 }
3760 if (strcmp(buffer, "[Angband config, Musus' port]\n"))
3761 {
3762 fclose(fp);
3763 return;
3764 }
3765
3766 /* Load choices */
3767 while (fgets(buffer, sizeof(buffer), fp))
3768 {
3769 t_ = strtok(buffer, " "); /* Term number (or keyword, "Gamma", etc.) */
3770 o_ = strtok(NULL, "\n"); /* argument string */
3771 if (!o_)
3772 {
3773 o_ = "";
3774 } /* missing (or null) argument? */
3775 if (t_)
3776 {
3777 if (!strcmp(t_, "Gamma"))
3778 gamma = atof(o_);
3779 else if (!strcmp(t_, "Monochrome"))
3780 force_mono = !strcmp(o_, "on");
3781 else if (!strcmp(t_, "Sound"))
3782 enable_sound = !strcmp(o_, "on");
3783 else if (!strcmp(t_, "Volume"))
3784 sound_volume = atoi(o_);
3785 else if (!strcmp(t_, "FullScreen"))
3786 start_fullscreen = !strcmp(o_, "on");
3787 else if (!strcmp(t_, "Hourglass"))
3788 use_glass = !strcmp(o_, "on");
3789 else if (!strcmp(t_, "HackFlush"))
3790 hack_flush = !strcmp(o_, "on");
3791 else if (!strcmp(t_, "AlarmTimeH"))
3792 alarm_h = atoi(o_);
3793 else if (!strcmp(t_, "AlarmTimeM"))
3794 alarm_m = atoi(o_);
3795 else if (!strcmp(t_, "AlarmText"))
3796 strcpy(alarm_message, o_);
3797 else if (!strcmp(t_, "AlarmBeep"))
3798 alarm_beep = !strcmp(o_, "on");
3799 else if (!strcmp(t_, "AlarmType"))
3800 {
3801 int i;
3802 for (i = 0; i < 4; i++)
3803 if (!strcmp(alarm_types[i], o_))
3804 alarm_type = i;
3805 }
3806 else if (isdigit((unsigned char)*t_))
3807 {
3808 int t = atoi(t_);
3809 if (t >= 0 && t < MAX_TERM_DATA)
3810 {
3811 char *f_, *x0_, *y0_, *x1_, *y1_, *sx_, *sy_;
3812 o_ = strtok(o_, " "); /* first word */
3813 f_ = strtok(NULL, " "); /* font name */
3814 x0_ = strtok(NULL, " "); /* x posn (min) */
3815 y0_ = strtok(NULL, " "); /* y posn (min) */
3816 x1_ = strtok(NULL, " "); /* x posn (max) */
3817 y1_ = strtok(NULL, " "); /* y posn (max) */
3818 sx_ = strtok(NULL, " "); /* x scroll offset */
3819 sy_ = strtok(NULL, "\n"); /* y scroll offset */
3820 data[t].def_open = (t == 0) || atoi(o_);
3821 data[t].def_pos.min.x = atoi(x0_);
3822 data[t].def_pos.min.y = atoi(y0_);
3823 data[t].def_pos.max.x = atoi(x1_);
3824 data[t].def_pos.max.y = atoi(y1_);
3825 data[t].def_scroll.x = atoi(sx_);
3826 data[t].def_scroll.y = atoi(sy_);
3827 data[t].unopened = 1; /* ie. force def_pos */
3828 #ifndef FULLSCREEN_ONLY
3829 attach_font_to_term(&(data[t]), f_);
3830 #endif /* FULLSCREEN_ONLY */
3831 }
3832 }
3833 }
3834 }
3835 fclose(fp);
3836 }
3837
3838 #ifndef FULLSCREEN_ONLY
3839 /*
3840 | Fudge so that the main term is *always* fullsize
3841 */
3842 {
3843 int fw, fh;
3844
3845 set_up_zrb(&(data[0]));
3846 fw = zrb.r_charw << screen_eig.x;
3847 fh = zrb.r_charh << screen_eig.y;
3848 if (zrb.r_flags.bits.double_height)
3849 {
3850 fh *= 2;
3851 }
3852 fw *= 80;
3853 fh *= 24;
3854 data[0].def_pos.max.x = data[0].def_pos.min.x + fw;
3855 data[0].def_pos.max.y = data[0].def_pos.min.y + fh;
3856 data[0].def_scroll.x = 0;
3857 data[0].def_scroll.y = 0;
3858 }
3859 #endif /* FULLSCREEN_ONLY */
3860
3861
3862 }
3863
3864
3865
3866
save_choices(void)3867 static void save_choices(void)
3868 {
3869 FILE *fp = NULL;
3870 FILE *fpm = NULL;
3871 char *cf;
3872 int i;
3873
3874 write_alarm_choices();
3875
3876 cf = find_choices(TRUE);
3877 if (!*cf)
3878 {
3879 plog("Failed to locate writable choices file!");
3880 return;
3881 }
3882
3883 fp = fopen(cf, "w");
3884 if (!fp)
3885 {
3886 plog("Can't write choices file");
3887 return;
3888 }
3889
3890 fpm = fopen(find_choices_mirror(), "w");
3891
3892 f2printf(fp, fpm, "[Angband config, Musus' port]\n");
3893 f2printf(fp, fpm, "Gamma %.2lf\n", gamma);
3894 f2printf(fp, fpm, "Monochrome %s\n", force_mono ? "on" : "off");
3895 f2printf(fp, fpm, "Sound %s\n", enable_sound ? "on" : "off");
3896 f2printf(fp, fpm, "Volume %d\n", sound_volume);
3897 f2printf(fp, fpm, "FullScreen %s\n", start_fullscreen ? "on" : "off");
3898 f2printf(fp, fpm, "Hourglass %s\n", use_glass ? "on" : "off");
3899 f2printf(fp, fpm, "HackFlush %s\n", hack_flush ? "on" : "off");
3900
3901 for (i = 0; i < MAX_TERM_DATA; i++)
3902 {
3903 window_state ws;
3904 Wimp_GetWindowState(data[i].w, &ws);
3905 f2printf(fp, fpm, "%d %d %s ", i, ws.flags.data.open,
3906 data[i].font->name);
3907 f2printf(fp, fpm, "%d ", ws.openblock.screenrect.min.x);
3908 f2printf(fp, fpm, "%d ", ws.openblock.screenrect.min.y);
3909 f2printf(fp, fpm, "%d ", ws.openblock.screenrect.max.x);
3910 f2printf(fp, fpm, "%d ", ws.openblock.screenrect.max.y);
3911 f2printf(fp, fpm, "%d %d\n", ws.openblock.scroll.x,
3912 ws.openblock.scroll.y);
3913 }
3914
3915 fclose(fp);
3916
3917 if (fpm)
3918 {
3919 fclose(fpm);
3920 }
3921 }
3922
3923 /*
3924 | Update the Alarm choices file to reflect changed alarm settings.
3925 */
write_alarm_choices(void)3926 static void write_alarm_choices(void)
3927 {
3928 FILE *fp;
3929 char *cf;
3930
3931 /* Open the choices file for reading */
3932 cf = find_alarmfile(TRUE);
3933 if (!*cf)
3934 {
3935 plog("Can't determine Alarm file location!");
3936 return;
3937 }
3938
3939 fp = fopen(cf, "w");
3940 if (!fp)
3941 {
3942 plog("Can't write Alarm file");
3943 return;
3944 }
3945
3946 /* Write the new alarm options */
3947 fprintf(fp, "AlarmType %s\n", alarm_types[alarm_type]);
3948 fprintf(fp, "AlarmTimeH %d\n", alarm_h);
3949 fprintf(fp, "AlarmTimeM %d\n", alarm_m);
3950 fprintf(fp, "AlarmText %s\n", alarm_message);
3951 fprintf(fp, "AlarmBeep %s\n", alarm_beep ? "on" : "off");
3952
3953 fclose(fp);
3954 }
3955
3956 /*
3957 | Read the Alarm choices file.
3958 */
read_alarm_choices(void)3959 static void read_alarm_choices(void)
3960 {
3961 char buffer[260];
3962 FILE *fp;
3963 char *cf;
3964
3965 cf = find_alarmfile(FALSE);
3966 if (!*cf)
3967 {
3968 return;
3969 }
3970
3971 fp = fopen(cf, "r");
3972 if (fp)
3973 {
3974 const char *t_, *o_;
3975 /* Load choices */
3976 while (fgets(buffer, sizeof(buffer), fp))
3977 {
3978 t_ = strtok(buffer, " "); /* Keyword */
3979 o_ = strtok(NULL, "\n"); /* argument string */
3980 if (!o_)
3981 {
3982 o_ = "";
3983 } /* missing (or null) argument? */
3984 if (t_)
3985 {
3986 if (!strcmp(t_, "AlarmTimeH"))
3987 alarm_h = atoi(o_);
3988 else if (!strcmp(t_, "AlarmTimeM"))
3989 alarm_m = atoi(o_);
3990 else if (!strcmp(t_, "AlarmText"))
3991 strcpy(alarm_message, o_);
3992 else if (!strcmp(t_, "AlarmBeep"))
3993 alarm_beep = !strcmp(o_, "on");
3994 else if (!strcmp(t_, "AlarmType"))
3995 {
3996 int i;
3997 for (i = 0; i < 4; i++)
3998 if (!strcmp(alarm_types[i], o_))
3999 alarm_type = i;
4000 }
4001 }
4002 }
4003 fclose(fp);
4004 }
4005 }
4006
4007
4008
4009 #ifndef FULLSCREEN_ONLY
4010 /*
4011 | Handle selections from the term menu(s)
4012 */
Hnd_TermMenu(event_pollblock * pb,void * ref)4013 static BOOL Hnd_TermMenu(event_pollblock * pb, void *ref)
4014 {
4015 mouse_block mb;
4016 int i;
4017
4018 Wimp_GetPointerInfo(&mb);
4019
4020 switch (pb->data.selection[0])
4021 {
4022 case TERM_MENU_INFO: /* Info> */
4023 break;
4024 case TERM_MENU_FONT: /* Font> */
4025 /* Sub item selected? */
4026 if (pb->data.selection[1] == -1)
4027 {
4028 break;
4029 }
4030 handle_font_selection(pb->data.selection + 1);
4031 break;
4032 case TERM_MENU_WINDOWS: /* Windows> */
4033 if (pb->data.selection[1] == -1)
4034 {
4035 break;
4036 }
4037 i = pb->data.selection[1];
4038 {
4039 window_state ws;
4040 Wimp_GetWindowState(data[i].w, &ws);
4041 if (ws.flags.data.open)
4042 {
4043 if (!i)
4044 Hnd_MainClose(NULL, (void *)TRUE);
4045 else
4046 Window_Hide(data[i].w);
4047 }
4048 else
4049 {
4050 if (!i)
4051 {
4052 show_windows();
4053 grab_caret();
4054 }
4055 else
4056 {
4057 if (!data[i].unopened)
4058 {
4059 Window_Show(data[i].w, open_WHEREVER);
4060 }
4061 else
4062 {
4063 window_openblock ob;
4064 ob.window = data[i].w;
4065 ob.screenrect = data[i].def_pos;
4066 ob.scroll = data[i].def_scroll;
4067 ob.behind = -1; /* could use data[0].w; ? */
4068 Wimp_OpenWindow(&ob);
4069 data[i].unopened = 0;
4070 }
4071 }
4072 }
4073 }
4074 break;
4075 }
4076
4077 if (mb.button.data.adjust)
4078 {
4079 set_up_term_menu(menu_term);
4080 Menu_ShowLast();
4081 }
4082
4083 return TRUE;
4084 }
4085
4086
4087
4088
4089
4090
4091 /*
4092 | Handle selections from the iconbar menu
4093 */
Hnd_IbarMenu(event_pollblock * pb,void * ref)4094 static BOOL Hnd_IbarMenu(event_pollblock * pb, void *ref)
4095 {
4096 mouse_block mb;
4097 Wimp_GetPointerInfo(&mb);
4098
4099 switch (pb->data.selection[0])
4100 {
4101 case IBAR_MENU_INFO: /* Info> */
4102 break;
4103 case IBAR_MENU_FULLSCREEN: /* Full screen */
4104 /* Do Full Screen mode */
4105 enter_fullscreen_mode();
4106 break;
4107 case IBAR_MENU_GAMMA: /* Gamma correction */
4108 break;
4109 case IBAR_MENU_SOUND: /* Sound */
4110 /*
4111 | enable_sound = !enable_sound;
4112 | if ( enable_sound ) { initialise_sound(); }
4113 | Menu_SetFlags( ibar_menu, IBAR_MENU_SOUND, enable_sound, 0 );
4114 | set_sound_window_state();
4115 */
4116 break;
4117 case IBAR_MENU_WINDOWS: /* Windows> */
4118 /*
4119 | Hack: pass it off as the equivalent selection from
4120 | the term menu.
4121 */
4122 pb->data.selection[0] = TERM_MENU_WINDOWS;
4123 return Hnd_TermMenu(pb, ref);
4124 break;
4125 case IBAR_MENU_SAVECHOICES: /* Save choices */
4126 save_choices();
4127 break;
4128 case IBAR_MENU_QUIT: /* Quit */
4129 if (game_in_progress && character_generated)
4130 save_player();
4131 quit(NULL);
4132 break;
4133 }
4134
4135 if (mb.button.data.adjust)
4136 Menu_ShowLast();
4137
4138 return TRUE;
4139 }
4140
4141
4142
4143
4144
Hnd_MenuSel(event_pollblock * pb,void * ref)4145 static BOOL Hnd_MenuSel(event_pollblock * pb, void *ref)
4146 {
4147 if (menu_currentopen == ibar_menu)
4148 return Hnd_IbarMenu(pb, ref);
4149 else if (menu_currentopen == term_menu)
4150 return Hnd_TermMenu(pb, ref);
4151 return FALSE;
4152 }
4153
4154
Hnd_IbarClick(event_pollblock * pb,void * ref)4155 static BOOL Hnd_IbarClick(event_pollblock * pb, void *ref)
4156 {
4157 if (pb->data.mouse.button.data.menu)
4158 {
4159 set_gamma_window_state();
4160 set_sound_window_state();
4161
4162 /* Hack: shade the Save> option if appropriate */
4163 if (game_in_progress && character_generated)
4164 Menu_SetFlags(ibar_menu, IBAR_MENU_SAVE, 0, PDEADCHK);
4165 else
4166 Menu_SetFlags(ibar_menu, IBAR_MENU_SAVE, 0, TRUE);
4167
4168 /*
4169 | Hack: set up the Term menu as if it was opened over the main
4170 | window (so that the Windows> submenu is set correctly)
4171 */
4172 menu_term = (term_data *)&data[0];
4173 set_up_term_menu(menu_term);
4174
4175 Menu_Show(ibar_menu, pb->data.mouse.pos.x, -1);
4176 return TRUE;
4177 }
4178
4179 if (pb->data.mouse.button.data.select)
4180 {
4181 show_windows();
4182 grab_caret();
4183 return TRUE;
4184 }
4185
4186 if (pb->data.mouse.button.data.adjust)
4187 {
4188 enter_fullscreen_mode();
4189 return TRUE;
4190 }
4191
4192 return FALSE;
4193 }
4194
4195
4196
4197 /*
4198 * Handler for NULL events (should this check the alarm in the desktop?
4199 */
Hnd_null(event_pollblock * event,void * ref)4200 static BOOL Hnd_null(event_pollblock *event, void *ref)
4201 {
4202 /* Really no need to check the alarm more than twice per second. */
4203 if (alarm_type && Time_Monotonic() > alarm_lastcheck + 200)
4204 {
4205 check_alarm();
4206 }
4207
4208 return TRUE;
4209 }
4210
4211
4212
4213
4214 /*
4215 | Handler for PreQuit messages (eg. at shutdown).
4216 */
Hnd_PreQuit(event_pollblock * b,void * ref)4217 static BOOL Hnd_PreQuit(event_pollblock * b, void *ref)
4218 {
4219 BOOL shutdown = (b->data.message.data.words[0] & 1) == 0;
4220 task_handle originator = b->data.message.header.sender;
4221 unsigned int quitref;
4222 message_block mb;
4223 char buffer1[64];
4224 os_error e;
4225 int ok;
4226
4227 if (!(game_in_progress && character_generated))
4228 return TRUE; /* ignore, we're OK to die */
4229
4230 /* Stop the shutdown/quit */
4231 memcpy(&mb, &(b->data.message), 24);
4232 quitref = mb.header.yourref;
4233 mb.header.yourref = mb.header.myref;
4234 Wimp_SendMessage(event_ACK, &mb, originator, 0);
4235
4236 /*
4237 | We handle this differently depending on the version of the Wimp;
4238 | newer versions give us much more flexibility.
4239 */
4240 if (event_wimpversion < 350)
4241 {
4242 /*
4243 | Older versions - use 'OK' and 'Cancel'.
4244 | There is no "Save & Quit" button.
4245 */
4246 Msgs_Lookup("err.shuttitl:Query from %s", e.errmess, 64);
4247 sprintf(buffer1, e.errmess, VARIANT);
4248 Msgs_Lookup("err.shutdown:Unsaved game; are you sure you want to quit?",
4249 e.errmess, 260);
4250 e.errnum = 0;
4251 SWI(3, 2, SWI_Wimp_ReportError, &e, 3 | 16, buffer1, NULL, &ok);
4252
4253 if (ok != 1)
4254 return TRUE; /* no! Pleeeeeease don't kill leeeeddle ol' me! */
4255 }
4256 else
4257 {
4258 /*
4259 | Newer version: can add buttons to the dialog.
4260 | we add a 'Save and Quit' button to allow the shutdown to
4261 | continue /after/ saving.
4262 */
4263 int flags;
4264 char buttons[64];
4265
4266 Msgs_Lookup("err.shutbuts:Save & quit,Don't quit,Quit anyway",
4267 buttons, 64);
4268 Msgs_Lookup("err.shuttitl:Query from %s", e.errmess, 64);
4269 sprintf(buffer1, e.errmess, VARIANT);
4270 Msgs_Lookup("err.shutdown:Unsaved game; are you sure you want to quit?",
4271 e.errmess, 260);
4272 e.errnum = 0;
4273
4274 flags = 0 | 16 | 256 | (4 << 9);
4275
4276 SWI(6, 2, SWI_Wimp_ReportError, &e, flags, buffer1, ICONNAME, 0,
4277 buttons, NULL, &ok);
4278
4279 if (ok == 4)
4280 return TRUE; /* no! Pleeeeeease don't kill leeeeddle ol' me! */
4281
4282 if (ok == 3)
4283 save_player(); /* Save & Quit */
4284 }
4285
4286
4287 /* RO2 doesn't use the shudown flag */
4288 if (shutdown && event_wimpversion >= 300 && mb.header.size >= 24)
4289 {
4290 key_block kb;
4291 kb.code = 0x1fc; /* restart shutdown sequence */
4292 Wimp_SendMessage(event_KEY, (message_block *) & kb, originator, 0);
4293 }
4294
4295 /* "Time... to die." */
4296 Event_CloseDown();
4297 exit(0);
4298 return TRUE; /* The one great certainty (sic) */
4299 }
4300
4301 #endif /* FULLSCREEN_ONLY */
4302
4303
4304
4305
initialise_terms(void)4306 static void initialise_terms(void)
4307 {
4308 char t[80];
4309 int i;
4310
4311 #ifndef FULLSCREEN_ONLY
4312 if (!minimise_memory)
4313 {
4314 /* Create a window for each term. Term 0 is special (no scroll bars) */
4315 data[0].w = Window_Create("angband", template_TITLEMIN);
4316 data[0].font = SYSTEM_FONT;
4317 data[0].def_open = 1;
4318 data[0].unopened = 1;
4319 sprintf(t, "%s %s", VARIANT, VERSION);
4320 Window_SetTitle(data[0].w, t);
4321 strncpy(data[0].name, VARIANT, 12);
4322 Event_Claim(event_KEY, data[0].w, event_ANY, Hnd_Keypress,
4323 (void *)&(data[0]));
4324 Event_Claim(event_REDRAW, data[0].w, event_ANY, Hnd_Redraw,
4325 (void *)&(data[0]));
4326 Event_Claim(event_CLICK, data[0].w, event_ANY, Hnd_TermClick,
4327 (void *)&(data[0]));
4328 Event_Claim(event_CLOSE, data[0].w, event_ANY, Hnd_MainClose, NULL);
4329
4330 for (i = 1; i < MAX_TERM_DATA; i++)
4331 {
4332 data[i].w = Window_Create("term", template_TITLEMIN);
4333 data[i].font = SYSTEM_FONT;
4334 data[i].def_open = 0;
4335 data[i].unopened = 1;
4336 #ifndef OLD_TERM_MENU
4337 sprintf(t, "%s (%s %s)", angband_term_name[i], VARIANT, VERSION);
4338 #else
4339 sprintf(t, "Term-%d (%s %s)", i, VARIANT, VERSION);
4340 #endif
4341 Window_SetTitle(data[i].w, t);
4342 strncpy(data[i].name, t, 12);
4343 Event_Claim(event_CLICK, data[i].w, event_ANY, Hnd_TermClick,
4344 (void *)&(data[i]));
4345 Event_Claim(event_REDRAW, data[i].w, event_ANY, Hnd_Redraw,
4346 (void *)&(data[i]));
4347 }
4348 }
4349 #endif /* FULLSCREEN_ONLY */
4350
4351 term_data_link(&(data[0]), 256);
4352
4353 for (i = 1; i < MAX_TERM_DATA; i++)
4354 {
4355 term_data_link(&(data[i]), 16);
4356 angband_term[i] = &(data[i].t);
4357 }
4358
4359 angband_term[0] = &(data[0].t);
4360 Term_activate(&(data[0].t));
4361 }
4362
4363
4364
4365
4366 /*
4367 | Hack(ish) - determine the version of RISC OS
4368 */
os_version(void)4369 static int os_version(void)
4370 {
4371 int osv;
4372 SWI(3, 2, SWI_OS_Byte, 129, 0, 255, NULL, &osv);
4373 switch (osv)
4374 {
4375 case 0xa0: return 120;
4376 case 0xa1: return 200;
4377 case 0xa2: return 201;
4378 case 0xa3: return 300;
4379 case 0xa4: return 310;
4380 case 0xa5: return 350;
4381 case 0xa6: return 360;
4382 case 0xa7: return 370;
4383 case 0xa8: return 400;
4384 default: return 370;
4385 }
4386 return -1; /* -sigh- */
4387 }
4388
4389 #ifndef FULLSCREEN_ONLY
4390 /*
4391 | Determine whether the current screen mode is "high-res"
4392 | (ie. should we use the "Sprites22" or the "Sprites" file.
4393 */
sprites22(void)4394 static int sprites22(void)
4395 {
4396 int yeig;
4397
4398 OS_ReadModeVariable(-1, modevar_YEIGFACTOR, &yeig);
4399
4400 return yeig < 2;
4401 }
4402
4403 /*
4404 | Determine whether we should use 2D or 3D templates.
4405 | 2D templates *must* be used under Wimp <3.00, but under RO3 we
4406 | use the CMOS settings to decide.
4407 */
templates2d(void)4408 static int templates2d(void)
4409 {
4410 int r1, r2;
4411
4412 if (event_wimpversion < 300)
4413 return TRUE;
4414
4415 /* The 3D bit is bit 0 of byte 140 */
4416 OS_Byte(osbyte_READCMOSRAM, 140, 0, &r1, &r2);
4417
4418 return !(r2 && 1);
4419 }
4420 #endif /* FULLSCREEN_ONLY */
4421
4422
4423
htoi(char * s)4424 static unsigned int htoi(char *s)
4425 {
4426 static const char hex[] = "0123456789ABCDEF";
4427 unsigned int v = 0;
4428 while (*s)
4429 {
4430 char *m;
4431 int d = toupper((unsigned char)*s++);
4432 m = strchr(hex, d);
4433 if (!m)
4434 {
4435 return v;
4436 }
4437 v = (v << 4) + (m - hex);
4438 }
4439 return v;
4440 }
4441
read_unsigned(char * t)4442 static int read_unsigned(char *t)
4443 {
4444 int r;
4445 if (SWI(2, 3, SWI_OS_ReadUnsigned, 2, t, NULL, NULL, &r))
4446 r = 0;
4447 return r;
4448 }
4449
4450 /*
4451 | Scan the string at 'n', replacing dodgy characters with underbars
4452 */
sanitise_name(char * n)4453 static void sanitise_name(char *n)
4454 {
4455 for (; *n; n++)
4456 {
4457 if (strchr("\"$%^&*\\\'@#.,", *n))
4458 *n = '_';
4459 }
4460 }
4461
4462
4463 /*
4464 | Ensure that the path to a given object exists.
4465 | Ie. if |p| = "a.b.c.d" then we attempt to
4466 | create directories a, a.b and a.b.c if they don't
4467 | already exist.
4468 | Note that 'd' may be absent.
4469 */
ensure_path(char * p)4470 static int ensure_path(char *p)
4471 {
4472 char tmp[260];
4473 char *l = tmp;
4474
4475 while (*p)
4476 {
4477 if (*p == '.')
4478 {
4479 *l = 0;
4480 if (SWI(5, 0, SWI_OS_File, 8, tmp, 0, 0, 77))
4481 return 0; /* Eeek! */
4482 }
4483 *l++ = *p++;
4484 }
4485
4486 return 1;
4487 }
4488
4489
4490 /*
4491 * Set up the Scrap, Choices and Alarm paths, trying for
4492 * Choices:blah...,etc. by preference, but falling back on lib/xtra
4493 * if need be.
4494 */
init_paths(void)4495 static void init_paths(void)
4496 {
4497 char tmp[512];
4498 char subpath[128];
4499 char *v;
4500 char *t;
4501
4502 /* Form the sub-path we use for both Choices and Scrap dirs: */
4503 v = subpath + sprintf(subpath, "%s", VARIANT);
4504 sanitise_name(subpath);
4505 sprintf(v, ".%s", VERSION);
4506 sanitise_name(v + 1);
4507
4508 /* Do the Scrap path first: */
4509 *scrap_path = 0;
4510
4511 /* Try for Wimp$ScrapDir... */
4512 t = getenv("Wimp$ScrapDir");
4513 if (t && *t)
4514 {
4515 sprintf(tmp, "%s.AngbandEtc.%s.", t, subpath);
4516 if (ensure_path(tmp))
4517 {
4518 strcpy(scrap_path, tmp);
4519 }
4520 }
4521
4522 /* Couldn't use Wimp$ScrapDir, so fall back on lib.xtra.scrap */
4523 if (!*scrap_path)
4524 {
4525 sprintf(tmp, "%sxtra.scrap.", resource_path);
4526 if (ensure_path(tmp))
4527 {
4528 strcpy(scrap_path, tmp);
4529 }
4530 }
4531
4532 /* Now set up the Choices and Alarm files: */
4533
4534 /* Read only Choices file is always lib.xtra.Choices */
4535 sprintf(choices_file[CHFILE_READ], "%sXtra.Choices", resource_path);
4536 /* Default writable Choices file is the same */
4537 strcpy(choices_file[CHFILE_WRITE], choices_file[CHFILE_READ]);
4538 /* No default mirror Choices file */
4539 strcpy(choices_file[CHFILE_MIRROR], "");
4540
4541 /* Read only Alarm file is always lib.xtra.Alarm */
4542 sprintf(alarm_file[CHFILE_READ], "%sXtra.Alarm", resource_path);
4543 /* Default writable Alarm file is the same */
4544 strcpy(alarm_file[CHFILE_WRITE], alarm_file[CHFILE_READ]);
4545
4546 /* Try to use Choices$Path, etc. for the others... */
4547
4548 t = getenv("Choices$Write"); /* Ie. where choices should be written */
4549 if (t && *t)
4550 {
4551 /* Choices file: */
4552 sprintf(tmp, "%s.AngbandEtc.%s", t, subpath);
4553 if (ensure_path(tmp))
4554 {
4555 /* Use for writable file: */
4556 strcpy(choices_file[CHFILE_WRITE], tmp);
4557 /* Form 'mirror' filename: same path but with a fixed leafname */
4558 strcpy(v + 1, "Default");
4559 sprintf(tmp, "%s.AngbandEtc.%s", t, subpath);
4560 strcpy(choices_file[CHFILE_MIRROR], tmp);
4561 }
4562
4563 /* Alarm file (doesn't involve subpath) */
4564 sprintf(tmp, "%s.AngbandEtc.Global.Alarm", t);
4565 if (ensure_path(tmp))
4566 {
4567 /* Use for read/writable file */
4568 strcpy(alarm_file[CHFILE_WRITE], tmp);
4569 }
4570 }
4571 }
4572
4573
4574
4575
4576
4577
4578
4579 /*
4580 * Return the appropriate (full) pathname.
4581 *
4582 * For write ops, the read/write file is returned.
4583 *
4584 * For read ops, either the read/write file, the mirror file,
4585 * or the read only file will be returned as appropriate.
4586 */
find_choices(int write)4587 static char *find_choices(int write)
4588 {
4589 if (write)
4590 return choices_file[CHFILE_WRITE];
4591
4592 if (myFile_Size(choices_file[CHFILE_WRITE]) > 0)
4593 return choices_file[CHFILE_WRITE];
4594
4595 if (myFile_Size(choices_file[CHFILE_MIRROR]) > 0)
4596 return choices_file[CHFILE_MIRROR];
4597
4598 return choices_file[CHFILE_READ];
4599 }
4600
find_choices_mirror(void)4601 static char *find_choices_mirror(void)
4602 {
4603 return choices_file[CHFILE_MIRROR];
4604 }
4605
find_alarmfile(int write)4606 static char *find_alarmfile(int write)
4607 {
4608 if (write)
4609 return alarm_file[CHFILE_WRITE];
4610
4611 if (myFile_Size(alarm_file[CHFILE_WRITE]) > 0)
4612 return alarm_file[CHFILE_WRITE];
4613
4614 return alarm_file[CHFILE_READ];
4615 }
4616
4617
4618
4619
main(int argc,char * argv[])4620 int main(int argc, char *argv[])
4621 {
4622 int i, j;
4623 int start_full = 0;
4624 char *arg_savefile = 0;
4625 char *t;
4626 #ifdef USE_DA
4627 int da_font = 1, da_game = 1;
4628 #endif
4629
4630 atexit(final_acn); /* "I never did care about the little things." */
4631
4632 Start_Hourglass;
4633
4634 /* Parse arguments */
4635 for (i = 1; i < argc; i++)
4636 {
4637 if (argv[i][0] == '-')
4638 {
4639 switch (tolower((unsigned char)argv[i][1]))
4640 {
4641 case 'm':
4642 {
4643 /* Minimise Memory */
4644 minimise_memory = 1;
4645
4646 /* Break */
4647 break;
4648 }
4649 case 'c': /* -c[a][s][f][<n>] */
4650 for (j = 2; argv[i][j]; j++)
4651 {
4652 int on = isupper((unsigned char)argv[i][j]);
4653
4654 switch (tolower((unsigned char)argv[i][j]))
4655 {
4656 #ifdef ABBR_FILECACHE
4657 case 'a': abbr_filecache =
4658 on;
4659 break;
4660 case 'f': abbr_tmpfile =
4661 on;
4662 break;
4663 #endif
4664 #ifdef SMART_FILECACHE
4665 case 's': smart_filecache =
4666 on;
4667 break;
4668 #endif
4669
4670 case 'p': flush_scrap =
4671 !on;
4672 break;
4673
4674 default:
4675 if (isdigit((unsigned char)argv[i][j]))
4676 {
4677 max_file_cache_size =
4678 atoi(argv[i] + j) << 10;
4679 while (isdigit((unsigned char)argv[i][++j]))
4680 ;
4681 if (max_file_cache_size <= 0)
4682 {
4683 use_filecache = 0;
4684 }
4685 j--;
4686 }
4687 else
4688 {
4689 fprintf(stderr, "Unrecognised option: -c%s",
4690 argv[i] + j);
4691 exit(EXIT_FAILURE);
4692 }
4693 }
4694 }
4695 break;
4696 case 'w': /* -waitrelease */
4697 hack_flush = 1;
4698 break;
4699 case 'e': /* -Evil */
4700 allow_iclear_hack = 1;
4701 break;
4702 case 's': /* -s<savefile> */
4703 if (argv[i][2])
4704 arg_savefile = argv[i] + 2;
4705 break;
4706 case 'f': /* -fullscreen */
4707 start_full = 1;
4708 break;
4709 case 'h': /* -hourglass */
4710 use_glass = 1;
4711 break;
4712 case 't': /* -T<filetype> */
4713 if (argv[i][2])
4714 vfiletype = htoi(argv[i] + 2);
4715 break;
4716 #ifdef USE_DA
4717 case 'd': /* -df, -dg, -dc or -d : disable DAs */
4718 switch (tolower((unsigned char)argv[i][2]))
4719 {
4720 case 0: /* -d => disable both */
4721 da_font = da_game = 0;
4722 break;
4723 case 'f': /* -df => disable font only */
4724 da_font = 0;
4725 break;
4726 case 'g': /* -dg => disable game only */
4727 da_game = 0;
4728 break;
4729 }
4730 break;
4731 #endif
4732 case '%': /* -%<debug_opts> */
4733 {
4734 int v = read_unsigned(argv[i] + 2);
4735 log_g_malloc = v & 1;
4736 show_sound_alloc = v & 2;
4737 }
4738 break;
4739 default:
4740 fprintf(stderr, "Unrecognised option: %s", argv[i]);
4741 exit(EXIT_FAILURE);
4742 }
4743 }
4744 }
4745
4746 /* 1.27 - new handling of -minimise-memory: */
4747 #ifndef FULLSCREEN_ONLY
4748 if (minimise_memory)
4749 #endif /* FULLSCREEN_ONLY */
4750 {
4751 start_full = 1;
4752 fs_quit_key_text = "(fullscreen only mode)";
4753 }
4754 #ifdef USE_DA
4755 init_memory(da_font, da_game); /* Set up dynamic areas, etc. if possible */
4756
4757 /* Install memory allocation hooks */
4758 ralloc_aux = g_malloc;
4759 rnfree_aux = g_free;
4760 #endif
4761
4762 /* Install replacement error reporting routines */
4763 quit_aux = quit_hook;
4764 plog_aux = plog_hook;
4765 core_aux = core_hook;
4766
4767 /* Expand the (Angband) resource path */
4768 t = getenv(RISCOS_VARIANT "$Path");
4769 if (!t || !*t) Msgs_ReportFatal(0, "A resources path could not be formed.");
4770 strcpy(resource_path, t);
4771
4772 /* Decide where scrap, choices and alarm files live: */
4773 init_paths();
4774
4775 /* Hack: if no savefile specified, use a default */
4776 if (!arg_savefile)
4777 {
4778 arg_savefile = malloc(strlen(resource_path) + 32);
4779 if (!arg_savefile)
4780 {
4781 Msgs_ReportFatal(0, "err.mem");
4782 }
4783 sprintf(arg_savefile, "%s%s", resource_path, ">Save.Savefile");
4784 }
4785
4786 /* This crap appears here so that plog() will work properly before
4787 init_acn() is called... */
4788 Resource_Initialise(RISCOS_VARIANT);
4789 Msgs_LoadFile("Messages");
4790
4791 #ifndef FULLSCREEN_ONLY
4792 if (!minimise_memory)
4793 {
4794 /* This is a hack to only call Event_Initialise3 under RO3 */
4795 if (os_version() < 300)
4796 Event_Initialise(RISCOS_VARIANT);
4797 else
4798 Event_Initialise3(RISCOS_VARIANT, 300, message_list);
4799
4800 EventMsg_Initialise();
4801
4802 /*
4803 | This is a possible workaround for the FP regs getting
4804 | bolloxed in the ! menu because the compiler sets them
4805 | up before a call to Wimp_Poll if CSE optimisation is on.
4806 | At the moment I've just turned off CSE for the function
4807 | affected.
4808 |
4809 | event_mask.data.keepfpregisters = 1;
4810 */
4811
4812 /* Load Templates */
4813 Template_Initialise();
4814 if (templates2d())
4815 Template_LoadFile("Templates2");
4816 else
4817 Template_LoadFile("Templates");
4818
4819 /* Load Sprites */
4820 if (sprites22())
4821 resource_sprites =
4822 Sprite_LoadFile("<" RISCOS_VARIANT "$Dir>.Sprites22");
4823 else
4824 resource_sprites = Sprite_LoadFile("<" RISCOS_VARIANT "$Dir>.Sprites");
4825 }
4826 #endif /* FULLSCREEN_ONLY */
4827
4828 Screen_CacheModeInfo();
4829
4830 /* Initialise some ZapRedraw stuff */
4831 initialise_palette();
4832 initialise_fonts(); /* Set up the fonts */
4833 #ifndef FULLSCREEN_ONLY
4834 initialise_r_data(); /* Set up the r_data buffer */
4835
4836 if (!minimise_memory)
4837 {
4838 /* Initialise some Wimp specific stuff */
4839 init_gamma_window();
4840 init_sound_window();
4841 init_save_window();
4842 init_menus();
4843 ibar_icon = Icon_BarIcon(ICONNAME, iconbar_RIGHT);
4844
4845 /* Global handlers */
4846 Event_Claim(event_OPEN, event_ANY, event_ANY, Handler_OpenWindow, NULL);
4847 Event_Claim(event_CLOSE, event_ANY, event_ANY, Handler_CloseWindow, NULL);
4848 Event_Claim(event_GAINCARET, event_ANY, event_ANY, Hnd_Caret, (void *)1);
4849 Event_Claim(event_LOSECARET, event_ANY, event_ANY, Hnd_Caret, (void *)0);
4850 Event_Claim(event_MENU, event_ANY, event_ANY, Hnd_MenuSel, NULL);
4851 Event_Claim(event_CLICK, window_ICONBAR, ibar_icon, Hnd_IbarClick, NULL);
4852 Event_Claim(event_CLICK, event_ANY, event_ANY, Hnd_Click, NULL);
4853 EventMsg_Claim(message_PALETTECHANGE, event_ANY, Hnd_PaletteChange, NULL);
4854 EventMsg_Claim(message_MODECHANGE, event_ANY, Hnd_ModeChange, NULL);
4855 EventMsg_Claim(message_PREQUIT, event_ANY, Hnd_PreQuit, NULL);
4856
4857 /* Initialise the sound stuff */
4858 initialise_sound();
4859 }
4860 #endif /* FULLSCREEN_ONLY */
4861
4862 /* Initialise some Angband stuff */
4863 initialise_terms();
4864 load_choices();
4865 read_alarm_choices();
4866 init_file_paths(unixify_name(resource_path));
4867
4868 Start_Hourglass; /* Paranoia */
4869
4870 /* Hack - override the saved options if -F was on the command line */
4871 start_fullscreen |= start_full;
4872
4873 /* hack so that the cursor is yellow if undefined */
4874 if (palette[CURSOR_COLOUR] == palette[0])
4875 {
4876 angband_color_table[CURSOR_COLOUR][1] = (CURSOR_RGB & 0xff00) >> 8;
4877 angband_color_table[CURSOR_COLOUR][2] = (CURSOR_RGB & 0xff0000) >> 16;
4878 angband_color_table[CURSOR_COLOUR][3] = (CURSOR_RGB & 0xff000000) >> 24;
4879 }
4880
4881 /* Catch nasty signals */
4882 signals_init();
4883 /* use pref-acn.prf */
4884 ANGBAND_SYS = "acn";
4885
4886 #ifndef FULLSCREEN_ONLY
4887 if (start_fullscreen)
4888 {
4889 #endif /* FULLSCREEN_ONLY */
4890 enter_fullscreen_mode();
4891 #ifndef FULLSCREEN_ONLY
4892 }
4893 else
4894 {
4895 Start_Hourglass; /* Paranoia */
4896 Hnd_ModeChange(NULL, NULL); /* Caches the various fonts/palettes */
4897 show_windows();
4898 grab_caret();
4899
4900 Event_Claim(event_NULL, event_ANY, event_ANY, Hnd_null, NULL);
4901
4902 /* Wait for a null poll so that the windows can appear */
4903 do
4904 {
4905 Event_Poll();
4906 }
4907 while (event_lastevent.type != 0);
4908 }
4909 #endif /* FULLSCREEN_ONLY */
4910
4911 /* Initialise Angband */
4912 Start_Hourglass; /* Paranoia */
4913
4914 strncpy(savefile, unixify_name(arg_savefile), sizeof(savefile));
4915 savefile[sizeof(savefile) - 1] = '\0';
4916
4917 use_sound = 1;
4918 init_angband();
4919 initialised = 1;
4920 game_in_progress = 1;
4921 pause_line(23);
4922 flush();
4923 /* Stop_Hourglass; */
4924 play_game(FALSE);
4925
4926 if (fullscreen_mode) leave_fullscreen_mode();
4927
4928 Stop_Hourglass;
4929
4930 quit(NULL);
4931
4932 return 0;
4933
4934 debug("to stop the 'unused' warning :)");
4935 }
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949 /*--------------------------------------------------------------------------*/
4950 /* Stuff below here is for the full screen display */
4951 /*--------------------------------------------------------------------------*/
4952
4953 static errr Term_xtra_acn_checkFS(void);
4954 static errr Term_xtra_acn_eventFS(void);
4955 static errr Term_xtra_acn_reactFS(int force);
4956 static errr Term_curs_acnFS(int x, int y);
4957 static errr Term_xtra_acn_clearFS(void);
4958 static errr Term_xtra_acnFS(int n, int v);
4959 static errr Term_wipe_acnFS(int x, int y, int n);
4960 static errr Term_text_acnFS(int x, int y, int n, byte a, cptr s);
4961 static void bored(void);
4962 static void redraw_areaFS(int x, int y, int w, int h);
4963 static void draw_cursor(int x, int y);
4964
4965 /*
4966 | We use this to keep the mouse in the same place on return from full-screen
4967 | mode.
4968 */
4969 static unsigned char old_mouse_posn[5];
4970
4971 /*
4972 | Take a copy of the current mode descriptor/number and return either
4973 | a pointer to it (as an int) if it's a new mode, or the mode number.
4974 | NB: A static pointer is used and the descriptor returned is only
4975 | valid until the next call to this function.
4976 |
4977 | Basically, a replacement for OS_Byte 135 / OS_ScreenMode1, IYSWIM.
4978 */
current_mode(void)4979 static int current_mode(void)
4980 {
4981 static void *descriptor = NULL;
4982 int mode;
4983 int size;
4984 int i;
4985 int *vals;
4986
4987 if (descriptor)
4988 {
4989 free(descriptor);
4990 descriptor = NULL;
4991 }
4992
4993 SWI(1, 3, SWI_OS_Byte, 135, NULL, NULL, &mode);
4994 if (mode < 256)
4995 {
4996 return mode;
4997 }
4998
4999 vals = (int *)(mode + 20);
5000 for (i = 0; vals[i] != -1; i += 2)
5001 ;
5002
5003 size = 24 + 8 * i; /* Size of data */
5004 descriptor = malloc(size);
5005 if (!descriptor)
5006 {
5007 core("Out of memory!");
5008 }
5009 memcpy(descriptor, (void *)mode, size);
5010
5011 return (int)descriptor;
5012 }
5013
5014
5015
5016 /*
5017 | Select the best mode we can for full screen.
5018 | Returns 12 for (low-res, ie. mode 12) or 27 for high-res,
5019 | or a pointer to a mode descriptor (as an int).
5020 */
select_fullscreen_mode(void)5021 static int select_fullscreen_mode(void)
5022 {
5023 static struct
5024 {
5025 int flags, x, y, l2bpp, hz, term;
5026 }
5027 desc;
5028 int mode = 0;
5029
5030 desc.flags = 1; /* format 0 */
5031 desc.x = 640;
5032 desc.y = 480; /* 640x480 */
5033 desc.l2bpp = 2; /* 16 colours */
5034 desc.hz = -1; /* best we can get */
5035 desc.term = -1; /* don't fuss about modevars */
5036
5037 SWI(1, 1, SWI_OS_CheckModeValid, &desc, &mode);
5038 if (mode != (int)&desc)
5039 {
5040 SWI(1, 1, SWI_OS_CheckModeValid, 27, /**/ &mode);
5041 if (mode != 27)
5042 {
5043 SWI(1, 1, SWI_OS_CheckModeValid, 12, /**/ &mode);
5044 if (mode != 12)
5045 {
5046 mode = 0;
5047 }
5048 }
5049 }
5050
5051 return mode;
5052 }
5053
5054
5055 /*
5056 | Change screen mode
5057 */
change_screenmode(int to)5058 static void change_screenmode(int to)
5059 {
5060 if (SWI(2, 0, SWI_OS_ScreenMode, 0, to))
5061 {
5062 if (to < 256)
5063 {
5064 GFX_VDU(22);
5065 GFX_VDU(to);
5066 }
5067 else
5068 {
5069 /* Finished with my woman / cos she couldn't help me with ... */
5070 core("Eeek! mode isn't valid, but it /should/ be...");
5071 }
5072 }
5073 }
5074
5075
5076 /*
5077 | Constrain the mouse pointer to a point - this means that the damn
5078 | hourglass won't move around with the mouse :)
5079 */
constrain_pointer(void)5080 static void constrain_pointer(void)
5081 {
5082 wimp_rect r;
5083 int ys = screen_eig.y == 1 ? 32 : 64; /* Cope with dbl height glass */
5084
5085 Screen_CacheModeInfo(); /* Make sure we know the screen size */
5086 r.min.x = r.max.x = screen_size.x - 32;
5087 r.min.y = r.max.y = screen_size.y - ys;
5088 Pointer_RestrictToRect(r);
5089 }
5090
5091
5092
5093
5094 /*
5095 | Convert a 1bpp bitmap into a 4bpp bitmap (bit flipped)
5096 */
byte_to_word_flipped(int b)5097 static int byte_to_word_flipped(int b)
5098 {
5099 int w;
5100 if (b & 128)
5101 {
5102 w = 0xf0000000;
5103 }
5104 else
5105 {
5106 w = 0;
5107 }
5108 if (b & 64)
5109 {
5110 w |= 0x0f000000;
5111 }
5112 if (b & 32)
5113 {
5114 w |= 0x00f00000;
5115 }
5116 if (b & 16)
5117 {
5118 w |= 0x000f0000;
5119 }
5120 if (b & 8)
5121 {
5122 w |= 0x0000f000;
5123 }
5124 if (b & 4)
5125 {
5126 w |= 0x00000f00;
5127 }
5128 if (b & 2)
5129 {
5130 w |= 0x000000f0;
5131 }
5132 if (b & 1)
5133 {
5134 w |= 0x0000000f;
5135 }
5136 return w;
5137 }
5138
5139
5140
5141
5142 /*
5143 | try to load the fallback fullscreen font and convert it to 4bpp
5144 */
cache_zapfontHR(void)5145 static int cache_zapfontHR(void)
5146 {
5147 int handle;
5148 unsigned int extent;
5149 char buffer[260];
5150 struct
5151 {
5152 char id[8];
5153 int w, h, f, l, r1, r2;
5154 }
5155 zfh;
5156 int *op;
5157 char *ip;
5158 int l, i;
5159
5160 /* Try to open the file */
5161 sprintf(buffer, "%s%s", resource_path, "xtra.FullScreen");
5162 handle = myFile_Open(buffer, 0x4f);
5163 if (!handle)
5164 {
5165 return 0;
5166 }
5167
5168 /* Check file's extent */
5169 extent = myFile_Extent(handle);
5170 if (extent > sizeof(zfh) + 256 * 16)
5171 {
5172 myFile_Close(handle);
5173 return 0;
5174 }
5175
5176 /* Load the header */
5177 if (myFile_ReadBytes(handle, &zfh, sizeof(zfh)))
5178 {
5179 myFile_Close(handle);
5180 return 0;
5181 }
5182
5183 /* Check font size */
5184 if ((zfh.w != 8) || (zfh.h > 16))
5185 {
5186 myFile_Close(handle);
5187 return 0;
5188 }
5189
5190 /* Load the 1bpp data */
5191 if (myFile_ReadBytes(handle, fullscreen_font, extent - sizeof(zfh)))
5192 {
5193 myFile_Close(handle);
5194 return 0;
5195 }
5196
5197 myFile_Close(handle);
5198
5199 l = zfh.l > 255 ? 255 : zfh.l;
5200
5201 if (zfh.h > 8)
5202 {
5203 op = (int *)(((int)fullscreen_font) + (l + 1) * zfh.h * 4);
5204 ip = (char *)(((int)fullscreen_font) + (l + 1) * zfh.h -
5205 (zfh.f * zfh.h));
5206 while (l-- >= zfh.f)
5207 {
5208 for (i = 0; i < zfh.h; i++)
5209 {
5210 *--op = byte_to_word_flipped(*--ip);
5211 }
5212 }
5213 fullscreen_height = zfh.h;
5214 }
5215 else
5216 {
5217 op = (int *)(((int)fullscreen_font) + (l + 1) * zfh.h * 8);
5218 ip = (char *)(((int)fullscreen_font) + (l + 1) * zfh.h -
5219 (zfh.f * zfh.h));
5220 while (l-- >= zfh.f)
5221 {
5222 for (i = -zfh.h; i < zfh.h; i++)
5223 {
5224 int t = byte_to_word_flipped(*--ip);
5225 *--op = t;
5226 *--op = t;
5227 }
5228 }
5229 fullscreen_height = zfh.h * 2;
5230 }
5231
5232 fullscreen_topline = TERM_TOPLINE_HR;
5233 fullscreen_topline += ((16 - fullscreen_height) * 13);
5234
5235 return 1;
5236 }
5237
5238
5239
5240
5241
cache_fs_fontHR(void)5242 static int cache_fs_fontHR(void)
5243 {
5244 ZapFont *src = SYSTEM_FONT;
5245 int c;
5246 int *op;
5247 char *ip;
5248
5249 /* Allocate the storage for the font */
5250 fullscreen_font = f_malloc(256 * 4 * 16);
5251 if (!fullscreen_font)
5252 {
5253 return 0;
5254 }
5255 op = (int *)fullscreen_font;
5256
5257 /* Check to see if the main term's font is suitable (ie. 8x16 or 8x8) */
5258 if ((data[0].font->w == 8) && (data[0].font->h <= 16))
5259 src = data[0].font;
5260
5261 /*
5262 | Hack: if we're forced to use the system font, try to load the
5263 | 'fullscreen' font from lib.xtra. If that fails, then I guess we're
5264 | stuck with the system font.
5265 */
5266
5267 if (src == SYSTEM_FONT)
5268 if (cache_zapfontHR())
5269 {
5270 return 1;
5271 }
5272
5273 ip = (char *)(src->bpp_1);
5274
5275 /* Now, create the font */
5276 if (src->h > 8)
5277 {
5278 int e = src->h * (src->l > 256 ? 256 : src->l);
5279 op += (src->f * src->h);
5280 for (c = src->f * src->h; c < e; c++)
5281 *op++ = byte_to_word_flipped(*ip++);
5282 fullscreen_height = src->h;
5283 }
5284 else
5285 {
5286 int e = src->h * (src->l > 256 ? 256 : src->l);
5287 op += (src->f * src->h) * 2;
5288 for (c = src->f * src->h; c < e; c++)
5289 {
5290 int t = byte_to_word_flipped(*ip++);
5291 *op++ = t;
5292 *op++ = t;
5293 }
5294 fullscreen_height = src->h * 2;
5295 }
5296
5297 fullscreen_topline = TERM_TOPLINE_HR;
5298 fullscreen_topline += ((16 - fullscreen_height) * 13);
5299
5300 return 1;
5301 }
5302
5303
5304
5305
5306
cache_fs_fontLR(void)5307 static int cache_fs_fontLR(void)
5308 {
5309 ZapFont *src = SYSTEM_FONT;
5310 int c, e;
5311 int *op;
5312 char *ip;
5313
5314 /* Allocate the storage for the font */
5315 fullscreen_font = f_malloc(256 * 4 * 8);
5316 if (!fullscreen_font)
5317 {
5318 return 0;
5319 }
5320 op = (int *)fullscreen_font;
5321
5322 /* Check to see if the main term's font is suitable (ie. 8x8) */
5323 if ((data[0].font->w == 8) && (data[0].font->h <= 8))
5324 src = data[0].font;
5325
5326 ip = (char *)(src->bpp_1);
5327
5328 /* Now, create the font */
5329 e = src->h * (src->l > 256 ? 256 : src->l);
5330 op += (src->f * src->h);
5331 for (c = src->f * src->h; c < e; c++)
5332 *op++ = byte_to_word_flipped(*ip++);
5333
5334 fullscreen_height = src->h;
5335 fullscreen_topline = TERM_TOPLINE_LR;
5336 fullscreen_topline += ((8 - fullscreen_height) * 13);
5337
5338 return 1;
5339 }
5340
5341
5342
set_keys(int claim)5343 static void set_keys(int claim)
5344 {
5345 static int old_c_state;
5346 static int old_f_state[8];
5347 int i;
5348
5349 if (claim)
5350 {
5351 /* Cursors/copy act as function keys */
5352 /* f0-f9, cursors, generate 0x80-0x8f */
5353 /* sh-f0-f9,cursors, generate 0x90-0x9f */
5354 /* ctrl f0-f9,cursors, generate 0xa0-0xaf */
5355 /* sh-c-f0-f9,cursors, generate 0xb0-0xbf */
5356 /* f10-f12 generate 0xca-0xcc */
5357 /* shift f10-f12 generate 0xda-0xdc */
5358 /* ctrl f10-f12 generate 0xea-0xec */
5359 /* ctrlshift f10-f12 generate 0xfa-0xfc */
5360
5361 SWI(3, 2, SWI_OS_Byte, 4, 2, 0, /**/ NULL, &old_c_state);
5362
5363 for (i = 0; i < 4; i++)
5364 {
5365 SWI(3, 2, SWI_OS_Byte, 225 + i, 0x80 + (i * 0x10), 0, NULL,
5366 old_f_state + i);
5367 SWI(3, 2, SWI_OS_Byte, 221 + i, 0xc0 + (i * 0x10), 0, NULL,
5368 old_f_state + i + 4);
5369 }
5370 }
5371 else
5372 {
5373 SWI(3, 0, SWI_OS_Byte, 4, old_c_state, 0);
5374 for (i = 0; i < 4; i++)
5375 {
5376 SWI(3, 0, SWI_OS_Byte, 225 + i, old_f_state[i], 0);
5377 SWI(3, 0, SWI_OS_Byte, 221 + i, old_f_state[i + 4], 0);
5378 }
5379 }
5380 }
5381
5382
5383
5384
5385
5386
5387 /*
5388 | Enter the full screen mode.
5389 |
5390 | Full screen display uses either mode 27 (if supported) and 8x16 fonts
5391 | (or system font 'twiddled' to double height), or mode 12 (if mode 27
5392 | is unavailable) and the system font (or an 8x8 font).
5393 |
5394 */
5395
enter_fullscreen_mode(void)5396 static void enter_fullscreen_mode(void)
5397 {
5398 int vduvars[2] =
5399 { 149, -1 };
5400 int i;
5401
5402 /* New in 1.18 - protect against 're-entracy' */
5403 if (fullscreen_font)
5404 return;
5405
5406 /* New in 1.20 - hack IClear out of the way */
5407 if (allow_iclear_hack)
5408 iclear_hack();
5409
5410 /* Remember where the mouse is */
5411 old_mouse_posn[0] = 4;
5412 SWI(2, 0, SWI_OS_Word, 21, &old_mouse_posn);
5413
5414 /* Choose the mode we want */
5415 fullscreen_mode = select_fullscreen_mode();
5416
5417 if (!fullscreen_mode)
5418 {
5419 plog("Unable to select a suitable screen mode (27 or 12)");
5420 return;
5421 }
5422
5423 if (!((fullscreen_mode == 12) ? cache_fs_fontLR() : cache_fs_fontHR()))
5424 {
5425 plog("Unable to cache a font for full screen mode");
5426 return;
5427 }
5428
5429 /* Read the current screen mode */
5430 /* SWI( 1,3, SWI_OS_Byte, 135, NULL, NULL, &old_screenmode ); */
5431 old_screenmode = current_mode();
5432
5433 Stop_Hourglass;
5434
5435 /* Change to the chosen screen mode */
5436 change_screenmode(fullscreen_mode);
5437
5438 /* Restrict the pointer */
5439 constrain_pointer();
5440
5441 /* Remove the cursors */
5442 SWI(0, 0, SWI_OS_RemoveCursors);
5443
5444 Start_Hourglass;
5445
5446 /* Get the base address of screen memory */
5447 SWI(2, 0, SWI_OS_ReadVduVariables, vduvars, vduvars);
5448 fullscreen_base = (int *)(vduvars[0]);
5449
5450 /* Fudge the Term interface */
5451 for (i = 0; i < MAX_TERM_DATA; i++)
5452 {
5453 term *t = &(data[i].t);
5454 t->xtra_hook = Term_xtra_acnFS;
5455 t->wipe_hook = Term_wipe_acnFS;
5456 t->curs_hook = Term_curs_acnFS;
5457 t->text_hook = Term_text_acnFS;
5458 }
5459
5460 /* Grab the palette */
5461 Term_xtra_acn_reactFS(TRUE);
5462
5463 /* Make sure that the keys work properly */
5464 set_keys(TRUE);
5465
5466 /* refresh the term */
5467 /*Term_activate( &(data[0].t) ); */
5468 redraw_areaFS(0, 0, 80, 24);
5469 if (data[0].cursor.visible)
5470 draw_cursor(data[0].cursor.pos.x, data[0].cursor.pos.y);
5471
5472 /* Display a reminder of how to get back... */
5473 /* Hack: disable force_mono */
5474 i = force_mono;
5475 force_mono = 0;
5476 Term_text_acnFS(0, TIME_LINE, strlen(fs_quit_key_text), 8,
5477 fs_quit_key_text);
5478 force_mono = i;
5479 }
5480
5481
5482
5483
leave_fullscreen_mode(void)5484 static void leave_fullscreen_mode(void)
5485 {
5486 int i;
5487
5488 /* New in 1.18 - protect against 're-entracy' */
5489 if (!fullscreen_font)
5490 return;
5491
5492 /* Restore the Term interface */
5493 for (i = 0; i < MAX_TERM_DATA; i++)
5494 {
5495 #ifndef FULLSCREEN_ONLY
5496 term *t = &(data[i].t);
5497 t->xtra_hook = Term_xtra_acn;
5498 t->wipe_hook = Term_wipe_acn;
5499 t->curs_hook = Term_curs_acn;
5500 t->text_hook = Term_text_acn;
5501 #endif
5502 mark_ood(&(data[i]), 0, 0, 80, 24);
5503 }
5504
5505 /* Deallocate the font */
5506 f_free(fullscreen_font);
5507 fullscreen_font = 0;
5508 fullscreen_mode = 0;
5509
5510 Stop_Hourglass;
5511
5512 /* Restore the screen mode */
5513 Wimp_SetMode(old_screenmode);
5514
5515 /* Restore the pointer position */
5516 old_mouse_posn[0] = 3;
5517 SWI(2, 0, SWI_OS_Word, 21, &old_mouse_posn);
5518
5519 Start_Hourglass;
5520
5521 /* Restore the various soft keys */
5522 set_keys(FALSE);
5523
5524 /* New in 1.20 Remove the IClear hack */
5525 if (allow_iclear_hack)
5526 remove_iclear_hack();
5527
5528 #ifndef FULLSCREEN_ONLY
5529 /* Refresh the windows - this probably isn't necessary anyway */
5530 if (!minimise_memory)
5531 refresh_windows();
5532 #endif /* FULLSCREEN_ONLY */
5533 }
5534
5535
5536
5537
5538
fs_writechars(int x,int y,int n,const char * chars,char attr)5539 static void fs_writechars(int x, int y, int n, const char *chars, char attr)
5540 {
5541 int *scr, *scrb;
5542 int *cdat;
5543 int j;
5544 unsigned int fgm;
5545
5546 if (force_mono)
5547 {
5548 if (attr != TERM_DARK)
5549 {
5550 attr = TERM_WHITE;
5551 }
5552 }
5553 fgm = (unsigned int)zpalette[(unsigned int) attr];
5554
5555 scrb = (int *)(((int)fullscreen_base) + y * fullscreen_height * 320
5556 + x * 4 + 320 * fullscreen_topline);
5557
5558 while (n--)
5559 {
5560 scr = scrb++;
5561 cdat = (int *)(((int)fullscreen_font)
5562 + (*chars++) * (fullscreen_height << 2));
5563 for (j = 0; j < fullscreen_height; j++)
5564 {
5565 *scr = *cdat++ & fgm;
5566 scr += 80;
5567 }
5568 }
5569 }
5570
5571
fs_writechar(int x,int y,char c,char attr)5572 static void fs_writechar(int x, int y, char c, char attr)
5573 {
5574 int *scrb;
5575 int *cdat;
5576 int j;
5577 unsigned int fgm;
5578
5579 if (force_mono)
5580 {
5581 if (attr != TERM_DARK)
5582 {
5583 attr = TERM_WHITE;
5584 }
5585 }
5586 fgm = (unsigned int)zpalette[(unsigned int) attr];
5587
5588 scrb = (int *)(((int)fullscreen_base) + y * fullscreen_height * 320
5589 + x * 4 + 320 * fullscreen_topline);
5590 cdat = (int *)(((int)fullscreen_font) + (c * (fullscreen_height << 2)));
5591 for (j = 0; j < fullscreen_height; j++)
5592 {
5593 *scrb = *cdat++ & fgm;
5594 scrb += 80;
5595 }
5596 }
5597
5598
5599
draw_cursorHR(int x,int y)5600 static void draw_cursorHR(int x, int y)
5601 {
5602 ColourTrans_SetGCOL(cursor_rgb, 0, 0);
5603 GFX_Move(x * 16,
5604 959 - y * (fullscreen_height * 2) - fullscreen_topline * 2);
5605 GFX_DrawBy(14, 0);
5606 GFX_DrawBy(0, -(fullscreen_height * 2 - 2));
5607 GFX_DrawBy(-14, 0);
5608 GFX_DrawBy(0, fullscreen_height * 2 - 2);
5609 }
5610
draw_cursorLR(int x,int y)5611 static void draw_cursorLR(int x, int y)
5612 {
5613 ColourTrans_SetGCOL(cursor_rgb, 0, 0);
5614 GFX_Move(x * 16,
5615 1023 - y * (fullscreen_height * 4) - fullscreen_topline * 4);
5616 GFX_DrawBy(14, 0);
5617 GFX_DrawBy(0, -(fullscreen_height * 4 - 4));
5618 GFX_DrawBy(-14, 0);
5619 GFX_DrawBy(0, fullscreen_height * 4 - 4);
5620 }
5621
5622
5623
5624
5625
draw_cursor(int x,int y)5626 static void draw_cursor(int x, int y)
5627 {
5628 if (fullscreen_mode == 12)
5629 draw_cursorLR(x, y);
5630 else
5631 draw_cursorHR(x, y);
5632 }
5633
5634
5635
redraw_areaFS(int x,int y,int w,int h)5636 static void redraw_areaFS(int x, int y, int w, int h)
5637 {
5638 int i, j;
5639 for (j = y; j < y + h; j++)
5640 for (i = x; i < x + w; i++)
5641 fs_writechar(i, j, data[0].t.old->c[j][i], data[0].t.old->a[j][i]);
5642 }
5643
5644
5645
wimp_code(int c)5646 static int wimp_code(int c)
5647 {
5648 /* shift/ctrl keypad? */
5649 if (c >= '0' && c <= '9')
5650 {
5651 kbd_modifiers m = Kbd_GetModifiers(FALSE);
5652 if (m.shift)
5653 {
5654 c |= 0x800;
5655 }
5656 if (m.ctrl)
5657 {
5658 c |= 0x400;
5659 }
5660 return c;
5661 }
5662 if (c == 9)
5663 {
5664 return 0x18a;
5665 } /* Tab */
5666 if (c <= 127)
5667 {
5668 return c;
5669 } /* normal ASCII/ctrl */
5670 if (c >= 0x80 && c <= 0xff)
5671 {
5672 return c + 0x100;
5673 } /* f0-f9, etc. */
5674
5675 return -1; /* unknown */
5676 }
5677
5678
5679
5680
do_keypress(int code)5681 static void do_keypress(int code)
5682 {
5683 static const char hex[] = "0123456789ABCDEF";
5684
5685 if (code == KEYPRESS_QUIT && !minimise_memory)
5686 {
5687 #ifdef FULLSCREEN_ONLY
5688 Sound_SysBeep();
5689 #else
5690 leave_fullscreen_mode();
5691 #endif
5692 return;
5693 }
5694
5695 if (code == 27)
5696 {
5697 if (Kbd_KeyDown(inkey_CTRL))
5698 {
5699 ack_alarm();
5700 return;
5701 }
5702 }
5703
5704 if (code <= 255)
5705 {
5706 Term_keypress(code);
5707 }
5708 else
5709 {
5710 Term_keypress(31);
5711 Term_keypress(hex[(code & 0xf00) >> 8]);
5712 Term_keypress(hex[(code & 0x0f0) >> 4]);
5713 Term_keypress(hex[(code & 0x00f)]);
5714 Term_keypress(13);
5715 }
5716 }
5717
5718
5719
5720
Term_xtra_acn_checkFS(void)5721 static errr Term_xtra_acn_checkFS(void)
5722 {
5723 int bh, bl;
5724 int c;
5725
5726 Stop_Hourglass;
5727
5728 bored();
5729
5730 SWI(3, 3, SWI_OS_Byte, 128, 255, 0, /**/ NULL, &bl, &bh);
5731 bl = (bl & 0xff) + (bh << 8);
5732
5733 if (bl > 0)
5734 {
5735 SWI(0, 1, SWI_OS_ReadC, &c);
5736 bl = wimp_code(c);
5737 if (bl >= 0)
5738 {
5739 do_keypress(bl);
5740 }
5741 }
5742
5743 Start_Hourglass;
5744
5745 return 0;
5746 }
5747
5748
5749
5750
Term_xtra_acn_eventFS(void)5751 static errr Term_xtra_acn_eventFS(void)
5752 {
5753 int c;
5754 int w = -1;
5755
5756 Stop_Hourglass;
5757
5758 for (w = -1; w == -1;)
5759 {
5760 int bh, bl;
5761 do
5762 {
5763 bored();
5764 SWI(3, 3, SWI_OS_Byte, 128, 255, 0, /**/ NULL, &bl, &bh);
5765 bl = (bl & 0xff) + (bh << 8);
5766 }
5767 while (!bl);
5768
5769 SWI(0, 1, SWI_OS_ReadC, &c);
5770 w = wimp_code(c);
5771 if (w >= 0)
5772 {
5773 do_keypress(w);
5774 }
5775 }
5776
5777 Start_Hourglass;
5778
5779 return 0;
5780 }
5781
5782
5783
5784 /*
5785 * React to changes
5786 */
Term_xtra_acn_reactFS(int force)5787 static errr Term_xtra_acn_reactFS(int force)
5788 {
5789 unsigned int i;
5790 int p, r, g, b;
5791
5792 static double old_gamma = -1.0;
5793
5794 if (gamma != old_gamma)
5795 {
5796 force = 1;
5797 old_gamma = gamma;
5798 }
5799
5800 /* Set the screen colours */
5801 for (i = 0; i < 16; i++)
5802 {
5803 if (COLOUR_CHANGED(i) || force)
5804 {
5805 r = (int)(255.0 *
5806 pow(angband_color_table[i][1] / 255.0, 1.0 / gamma));
5807 g = (int)(255.0 *
5808 pow(angband_color_table[i][2] / 255.0, 1.0 / gamma));
5809 b = (int)(255.0 *
5810 pow(angband_color_table[i][3] / 255.0, 1.0 / gamma));
5811 GFX_VDU(19);
5812 GFX_VDU(i);
5813 GFX_VDU(16);
5814 GFX_VDU(r);
5815 GFX_VDU(g);
5816 GFX_VDU(b);
5817
5818 palette[i] = (b << 24) | (g << 16) | (r << 8);
5819 p = i;
5820 p |= (p << 4);
5821 p |= (p << 8);
5822 p |= (p << 16);
5823 zpalette[i] = p;
5824
5825 a_palette[i][1] = angband_color_table[i][1];
5826 a_palette[i][2] = angband_color_table[i][2];
5827 a_palette[i][3] = angband_color_table[i][3];
5828
5829 /* Find any higher colour numbers and make them "wrong" */
5830 for (p = 16; p < 256; p++)
5831 if ((zpalette[p] & 0xf) == i)
5832 a_palette[p][1] = angband_color_table[p][1] + 2;
5833 }
5834 }
5835
5836
5837 /* Go through the palette updating any changed values */
5838 for (i = 16; i < 256; i++)
5839 {
5840 if (COLOUR_CHANGED(i) || force)
5841 {
5842 r = (int)(255.0 *
5843 pow(angband_color_table[i][1] / 255.0, 1.0 / gamma));
5844 g = (int)(255.0 *
5845 pow(angband_color_table[i][2] / 255.0, 1.0 / gamma));
5846 b = (int)(255.0 *
5847 pow(angband_color_table[i][3] / 255.0, 1.0 / gamma));
5848 p = (b << 24) | (g << 16) | (r << 8);
5849 palette[i] = p;
5850 SWI(1, 1, SWI_ColourTrans_ReturnColourNumber, palette[i], &p);
5851 p |= (p << 4);
5852 p |= (p << 8);
5853 p |= (p << 16);
5854 zpalette[i] = p;
5855 a_palette[i][1] = angband_color_table[i][1];
5856 a_palette[i][2] = angband_color_table[i][2];
5857 a_palette[i][3] = angband_color_table[i][3];
5858 }
5859 }
5860
5861 cursor_rgb = palette[CURSOR_COLOUR];
5862
5863 return 0;
5864 }
5865
5866
Term_curs_acnFS(int x,int y)5867 static errr Term_curs_acnFS(int x, int y)
5868 {
5869 if (Term == &(data[0].t))
5870 {
5871 if (data[0].cursor.visible)
5872 redraw_areaFS(data[0].cursor.pos.x, data[0].cursor.pos.y, 1, 1);
5873 data[0].cursor.pos.x = x;
5874 data[0].cursor.pos.y = y;
5875 if (data[0].cursor.visible)
5876 draw_cursor(x, y);
5877 }
5878 return 0;
5879 }
5880
Term_xtra_acn_clearFS(void)5881 static errr Term_xtra_acn_clearFS(void)
5882 {
5883 char e[80];
5884 int j;
5885
5886 if (Term == &(data[0].t))
5887 {
5888 for (j = 0; j < 80; j++)
5889 e[j] = ' ';
5890
5891 GFX_Wait();
5892
5893 for (j = 0; j < 24; j++)
5894 fs_writechars(0, j, 80, e, 0);
5895 }
5896
5897 return 0;
5898 }
5899
5900
5901
5902
5903
5904
5905
Term_xtra_acnFS(int n,int v)5906 static errr Term_xtra_acnFS(int n, int v)
5907 {
5908 term_data *t = (term_data *)Term;
5909
5910 switch (n)
5911 {
5912 case TERM_XTRA_EVENT:
5913 if (v)
5914 return Term_xtra_acn_eventFS();
5915 else
5916 return Term_xtra_acn_checkFS();
5917
5918 case TERM_XTRA_BORED:
5919 bored();
5920 return Term_xtra_acn_checkFS();
5921
5922 case TERM_XTRA_FLUSH:
5923 /* 1.21 - Hack: wait until no keys are pressed */
5924 if (hack_flush)
5925 for (v = 0; v != 0xff;)
5926 SWI(1, 2, SWI_OS_Byte, 122, 0, &v);
5927 SWI(3, 0, SWI_OS_Byte, 21, 0, 0); /* Flush Kbd buffer */
5928 return 0;
5929
5930 case TERM_XTRA_FRESH:
5931 return 0;
5932
5933 case TERM_XTRA_FROSH:
5934 return 0;
5935
5936 case TERM_XTRA_SHAPE:
5937 if (t == (&data[0]))
5938 {
5939 t->cursor.visible = v;
5940 if (v)
5941 draw_cursor(t->cursor.pos.x, t->cursor.pos.y);
5942 else
5943 redraw_areaFS(t->cursor.pos.x, t->cursor.pos.y, 1, 1);
5944 }
5945 return 0;
5946
5947 case TERM_XTRA_NOISE:
5948 Sound_SysBeep();
5949 return 0;
5950
5951 case TERM_XTRA_REACT:
5952 return Term_xtra_acn_reactFS(FALSE);
5953
5954 case TERM_XTRA_DELAY:
5955 if (v > 0)
5956 {
5957 unsigned int start = Time_Monotonic();
5958 v = (v + 5) / 10; /* Round to nearest cs */
5959 GFX_Wait();
5960 while ((Time_Monotonic() - start) < v)
5961 ;
5962 }
5963 return (0);
5964
5965 case TERM_XTRA_SOUND: /* Play a sound :) */
5966 if (enable_sound)
5967 {
5968 play_sound(v);
5969 }
5970 return 0;
5971
5972 default:
5973 return 1;
5974 }
5975 }
5976
Term_wipe_acnFS(int x,int y,int n)5977 static errr Term_wipe_acnFS(int x, int y, int n)
5978 {
5979 if (Term == &(data[0].t))
5980 while (n--)
5981 fs_writechar(x++, y, ' ', 0);
5982 return 0;
5983 }
5984
Term_text_acnFS(int x,int y,int n,byte a,cptr s)5985 static errr Term_text_acnFS(int x, int y, int n, byte a, cptr s)
5986 {
5987 if (Term == &(data[0].t))
5988 fs_writechars(x, y, n, s, (char)a);
5989 return 0;
5990 }
5991
5992
5993
bored()5994 static void bored()
5995 {
5996 static int last = -1;
5997 char ts[80];
5998 time_t ct;
5999 struct tm *lt;
6000 unsigned int l;
6001 int ofm;
6002 static int alarm_flash = 1;
6003
6004
6005 /* Really no need to check the alarm more than once per second. */
6006 if (alarm_type && Time_Monotonic() > alarm_lastcheck + 200)
6007 {
6008 check_alarm();
6009 }
6010
6011 l = Time_Monotonic();
6012 if ((l - last) < (alarm_flash ? 25 : 50))
6013 {
6014 return;
6015 }
6016 last = l;
6017
6018 time(&ct);
6019 lt = localtime(&ct);
6020 l = strftime(ts, 80, "%c %Z", lt);
6021
6022 /* Hack: disable force_mono around printing the time */
6023 ofm = force_mono;
6024 force_mono = 0;
6025
6026 /* Hack: Is the alarm supposed to be going off? */
6027 if (alarm_disp || alarm_flash)
6028 {
6029 char blk[60];
6030 int c = 8;
6031 if (!alarm_disp)
6032 {
6033 alarm_flash = 11;
6034 }
6035 switch (alarm_flash / 2)
6036 {
6037 case 4: sprintf(blk, "%-57s", alarm_cancel_text);
6038 break;
6039 case 5: sprintf(blk, "%-57s", fs_quit_key_text);
6040 break;
6041 default:
6042 c = alarm_flash & 1 ? TERM_RED : TERM_WHITE;
6043 sprintf(blk, "%02d:%02d %-51s", alarm_h, alarm_m,
6044 alarm_message);
6045 }
6046 fs_writechars(0, TIME_LINE, 57, blk, c);
6047 if (++alarm_flash > 11)
6048 {
6049 alarm_flash = 0;
6050 }
6051 }
6052
6053 /* Display time */
6054 fs_writechar(79 - l, TIME_LINE, ' ', 0);
6055 fs_writechars(80 - l, TIME_LINE, l, ts, 8);
6056
6057 force_mono = ofm;
6058 }
6059
6060
6061
6062
6063
6064
6065 #ifdef USE_DA
6066 /*--------------------------------------------------------------------------*/
6067 /* (Simple) Heap management (using OS_Heap) */
6068 /*--------------------------------------------------------------------------*/
6069
6070 typedef void *heap;
6071
Heap_Initialise(heap h,size_t size)6072 static os_error *Heap_Initialise(heap h, size_t size)
6073 {
6074 return SWI(4, 0, SWI_OS_Heap, 0, h, 0, size);
6075 }
6076
Heap_Claim(heap h,size_t size)6077 static void *Heap_Claim(heap h, size_t size)
6078 {
6079 void *fred;
6080 os_error *e;
6081 e = SWI(4, 3, SWI_OS_Heap, 2, h, 0, size, NULL, NULL, &fred);
6082 return e ? NULL : fred;
6083 }
6084
Heap_Release(heap h,void * block)6085 static os_error *Heap_Release(heap h, void *block)
6086 {
6087 return SWI(3, 0, SWI_OS_Heap, 3, h, block);
6088 }
6089
Heap_ChangeHeapSize(heap h,int resize_by)6090 static int Heap_ChangeHeapSize(heap h, int resize_by)
6091 {
6092 int by;
6093 SWI(4, 4, SWI_OS_Heap, 5, h, 0, resize_by, 0, 0, 0, &by);
6094 return by;
6095 }
6096
6097
6098
6099 /*--------------------------------------------------------------------------*/
6100 /* Stuff below here is for using Dynamic areas (under RO3.5+) */
6101 /*--------------------------------------------------------------------------*/
6102
6103 static int game_area = -1; /* The DA the game is using */
6104 static int font_area = -1; /* The DA the fonts are using */
6105
6106 static void *game_area_base; /* base address of game area */
6107 static void *font_area_base; /* base address of font area */
6108
6109 static int font_area_size; /* size of the fonts' DA */
6110 static int font_heap_size; /* size of the fonts' heap */
6111 static int game_area_size; /* size of the game's DA */
6112 static int game_heap_size; /* size of the game's heap */
6113
6114 #define MAX_F_DA_SIZE (2<<20) /* Max size of font area (2Mb) */
6115 #define MAX_G_DA_SIZE (4<<20) /* Max size of game area (4Mb) */
6116 #define SHRINK_GRAN (4<<10) /* Try to recalaim wastage > this (4Kb) */
6117
6118
6119 /*
6120 | Free dynamic areas when we exit
6121 */
cleanup_memory(void)6122 static void cleanup_memory(void)
6123 {
6124 if (game_area != -1)
6125 {
6126 SWI(2, 0, SWI_OS_DynamicArea, 1, game_area);
6127 game_area = -1;
6128 }
6129
6130 if (font_area != -1)
6131 {
6132 SWI(2, 0, SWI_OS_DynamicArea, 1, font_area);
6133 font_area = -1;
6134 }
6135
6136 }
6137
6138
6139
6140 /*
6141 | Set up the memory allocation stuff.
6142 | We check to see if DAs are possible and if so initialise two:
6143 | one for the game's use (via the rnalloc() hooks) and one for
6144 | our own use (for fonts, etc).
6145 |
6146 | Each area is created 16Kb in size, with a max size of 2/4Mb.
6147 |
6148 | If 'daf' is TRUE, an area is created for the fonts.
6149 | If 'dag' is TRUE, an area is created for the game.
6150 */
init_memory(int daf,int dag)6151 static void init_memory(int daf, int dag)
6152 {
6153 os_error *e = NULL;
6154
6155 if (!daf)
6156 {
6157 /* Paranoia */
6158 font_area = -1;
6159 font_area_base = 0;
6160 }
6161 else
6162 {
6163 e = SWI(9, 4, SWI_OS_DynamicArea, 0, /* Create */
6164 -1, /* Let OS allocate no. */
6165 16 << 10, /* Initial size */
6166 -1, /* Let OS allocate address */
6167 1 << 7, /* Cacheable, bufferable, RW */
6168 MAX_F_DA_SIZE, /* Max size */
6169 0, /* handler */
6170 0, /* handler workspace */
6171 VARIANT " font data", /* Name */
6172 /* */
6173 NULL, /* r0 */
6174 &font_area, /* area number allocated */
6175 NULL, /* r2 */
6176 &font_area_base /* base address of area */
6177 );
6178
6179 if (e)
6180 {
6181 game_area = font_area = -1;
6182 game_area_base = font_area_base = 0; /* paranoia */
6183 return;
6184 }
6185 else
6186 {
6187 e = SWI(2, 3, SWI_OS_DynamicArea, 2, font_area,
6188 NULL, NULL, &font_area_size);
6189 if (e)
6190 {
6191 Error_ReportFatal(e->errnum, "%d:%s", e->errmess);
6192 }
6193
6194 e = Heap_Initialise((heap) font_area_base, font_area_size);
6195 if (e)
6196 {
6197 Error_ReportFatal(e->errnum, "%d:%s", e->errmess);
6198 }
6199 font_heap_size = font_area_size;
6200 }
6201 }
6202
6203 /* Make sure DA(s) are removed when we quit */
6204 atexit(cleanup_memory);
6205
6206 if (!dag)
6207 {
6208 /* Paranoia */
6209 game_area = -1;
6210 game_area_base = 0;
6211 }
6212 else
6213 {
6214 e = SWI(9, 4, SWI_OS_DynamicArea, 0, /* Create */
6215 -1, /* Let OS allocate no. */
6216 16 << 10, /* Initial size */
6217 -1, /* Let OS allocate address */
6218 1 << 7, /* Cacheable, bufferable, RW */
6219 MAX_G_DA_SIZE, /* Max size */
6220 0, /* handler */
6221 0, /* handler workspace */
6222 VARIANT " game data", /* Name */
6223 /* */
6224 NULL, /* r0 */
6225 &game_area, /* area number allocated */
6226 NULL, /* r2 */
6227 &game_area_base /* base address of area */
6228 );
6229
6230 if (e)
6231 {
6232 game_area = -1;
6233 game_area_base = 0; /* paranoia */
6234 }
6235 else
6236 {
6237 e = SWI(2, 3, SWI_OS_DynamicArea, 2, game_area,
6238 NULL, NULL, &game_area_size);
6239 if (e)
6240 {
6241 Error_ReportFatal(e->errnum, "%d:%s", e->errmess);
6242 }
6243
6244 e = Heap_Initialise((heap) game_area_base, game_area_size);
6245 if (e)
6246 {
6247 Error_ReportFatal(e->errnum, "%d:%s", e->errmess);
6248 }
6249 game_heap_size = game_area_size;
6250 }
6251 }
6252 }
6253
grow_dynamicarea(int area,int by)6254 static int grow_dynamicarea(int area, int by)
6255 {
6256 os_error *e;
6257 e = SWI(2, 2, SWI_OS_ChangeDynamicArea, area, by, /**/ NULL, &by);
6258 /* Can't check errors since a 'failed' shrink returns one... */
6259 return by;
6260 }
6261
6262
6263 /*
6264 | Try to shrink the font-cache heap and area as much as possible.
6265 */
f_shrink_heap(void)6266 static void f_shrink_heap(void)
6267 {
6268 int s;
6269 /* Shrink the heap as far as possible */
6270 font_heap_size -=
6271 Heap_ChangeHeapSize((heap) font_area_base, -MAX_F_DA_SIZE);
6272 /* Shrink the dynamic area if necessary */
6273 s = font_area_size - font_heap_size;
6274 if (s >= SHRINK_GRAN)
6275 font_area_size -= grow_dynamicarea(font_area, -s);
6276 }
6277
6278 /*
6279 | Allocate a block of memory in the font heap
6280 */
f_malloc(size_t size)6281 static void *f_malloc(size_t size)
6282 {
6283 void *c;
6284 int s;
6285 if (font_area == -1)
6286 {
6287 return malloc(size);
6288 }
6289 c = Heap_Claim((heap) font_area_base, size);
6290
6291 if (!c)
6292 {
6293 /* The Claim failed. Try to grow the area by the size of the block */
6294 s = grow_dynamicarea(font_area, size + 64); /* 64 is overkill */
6295 if (!s)
6296 {
6297 return NULL;
6298 }
6299 font_area_size += s;
6300 s = font_area_size - font_heap_size;
6301 font_heap_size += Heap_ChangeHeapSize((heap) font_area_base, s);
6302 c = Heap_Claim((heap) font_area_base, size);
6303 if (c)
6304 {
6305 f_shrink_heap();
6306 }
6307 }
6308 return c;
6309 }
6310
6311
6312 /*
6313 | Free a block of memory in the font heap
6314 */
f_free(void * blk)6315 static void f_free(void *blk)
6316 {
6317 os_error *e;
6318 if (font_area == -1)
6319 {
6320 free(blk);
6321 return;
6322 }
6323 e = Heap_Release((heap) font_area_base, blk);
6324 if (e)
6325 Msgs_ReportFatal(e->errnum, "err.swi", __LINE__, e->errmess);
6326 f_shrink_heap();
6327 }
6328
6329
6330
6331
6332
6333 /*
6334 | Allocate a block of memory in the game heap
6335 */
g_malloc(huge size)6336 static vptr g_malloc(huge size)
6337 {
6338 void *c;
6339 int s;
6340
6341 if (game_area == -1)
6342 {
6343 return malloc((size_t) size);
6344 }
6345 c = Heap_Claim((heap) game_area_base, (size_t) size + 4);
6346 if (!c)
6347 {
6348 /* The Claim failed. Try to grow the area by the size of the block */
6349 s = grow_dynamicarea(game_area, (size_t) size + 64); /* 64 is overkill */
6350 if (!s)
6351 {
6352 return NULL;
6353 }
6354 game_area_size += s;
6355 s = game_area_size - game_heap_size;
6356 game_heap_size += Heap_ChangeHeapSize((heap) game_area_base, s);
6357 c = Heap_Claim((heap) game_area_base, (size_t) size + 4);
6358 }
6359
6360 if (c)
6361 {
6362 strcpy((char *)c, "MUSH");
6363 c = (void *)(((int)c) + 4);
6364 }
6365
6366 if (log_g_malloc)
6367 fprintf(stderr, "ralloc(%ld) == %p\n", (long)size, c);
6368
6369 return c;
6370 }
6371
6372
6373 /*
6374 | Free a block of memory in the game heap
6375 |
6376 | The 'len' is to be compatible with z-virt.c (we don't need/use it)
6377 | Returns NULL.
6378 */
g_free(vptr blk)6379 static vptr g_free(vptr blk)
6380 {
6381 os_error *e;
6382 int s;
6383
6384 if (game_area == -1)
6385 {
6386 free(blk);
6387 return NULL;
6388 }
6389
6390 if (log_g_malloc)
6391 fprintf(stderr, "rnfree(%p)\n", blk);
6392
6393 if (strncmp(((char *)blk) - 4, "MUSH", 4))
6394 core("game heap corrupt / bad attempt to free memory");
6395
6396 blk = (void *)(((int)blk) - 4);
6397
6398 e = Heap_Release((heap) game_area_base, blk);
6399 if (e)
6400 Msgs_ReportFatal(e->errnum, "err.swi", __LINE__, e->errmess);
6401
6402 /* Shrink the heap as far as possible */
6403 game_heap_size -=
6404 Heap_ChangeHeapSize((heap) game_area_base, -MAX_G_DA_SIZE);
6405
6406 /* Shrink the dynamic area if necessary */
6407 s = game_area_size - game_heap_size;
6408 if (s >= SHRINK_GRAN)
6409 game_area_size -= grow_dynamicarea(game_area, -s);
6410
6411 return NULL;
6412 }
6413
6414
6415 #endif /* USE_DA */
6416
6417
6418
6419 /*--------------------------------------------------------------------------*/
6420
6421 /*
6422 | New to 1.04: Sound support :)
6423 |
6424 | We use the PlayIt module (for convenience).
6425 |
6426 | The Lib/xtra/sound/sound.cfg file is used to map sample names onto
6427 | event names.
6428 |
6429 | Since textual names are used in the .cfg file, we need to have a lookup
6430 | table to translate them into numbers. At present we use the
6431 | angband_sound_name array defined in variable.c
6432 |
6433 | Since there can be multiple sounds for each event we need to use a
6434 | list to store them.
6435 */
6436
6437 /* NB: This will be clipped to 10 under RISC OS 2 */
6438 #define MAX_SAMPNAME_LEN 64
6439
6440
6441
6442
6443 /*
6444 | The list format:
6445 */
6446 typedef struct samp_node
6447 {
6448 char sample_name[MAX_SAMPNAME_LEN + 1]; /* Sample name */
6449 struct samp_node *next; /* -> next node */
6450 }
6451 SampNode;
6452
6453 typedef struct samp_info
6454 {
6455 int samples; /* # samples for this event */
6456 SampNode *samplist; /* list of sample names */
6457 }
6458 SampInfo;
6459
6460
6461 /*
6462 | Just need an array of SampInfos
6463 */
6464 static SampInfo sample[SOUND_MAX];
6465
6466 /*
6467 | This flag will only be set non-zero if the SampInfo array is
6468 | valid.
6469 */
6470 static int sound_initd = 0;
6471
6472
read_sound_config(void)6473 static void read_sound_config(void)
6474 {
6475 int i;
6476 char buffer[2048];
6477 FILE *f;
6478 int max_sampname_len = truncate_names()? 10 : MAX_SAMPNAME_LEN;
6479 FILE *dbo = NULL;
6480
6481 if (show_sound_alloc)
6482 {
6483 sprintf(buffer, "%s%s", resource_path, "sndmap/out");
6484 dbo = fopen(buffer, "w");
6485 if (!dbo)
6486 {
6487 core("can't create sndmap/out debugging file");
6488 }
6489 }
6490
6491 if (!sound_initd)
6492 {
6493 /* Initialise the sample array */
6494 for (i = 0; i < SOUND_MAX; i++)
6495 {
6496 sample[i].samples = 0;
6497 sample[i].samplist = NULL;
6498 }
6499 sound_initd = 1;
6500 }
6501 else
6502 {
6503 /* Deallocate the sample lists */
6504 for (i = 0; i < SOUND_MAX; i++)
6505 {
6506 SampNode *si = sample[i].samplist;
6507 sample[i].samples = 0;
6508 sample[i].samplist = NULL;
6509 while (si)
6510 {
6511 SampNode *ns = si->next;
6512 free(si);
6513 si = ns;
6514 }
6515 }
6516 }
6517
6518
6519 /* Open the config file */
6520 sprintf(buffer, "%sSound:%s", RISCOS_VARIANT, "sound/cfg");
6521 f = fopen(buffer, "r");
6522
6523 /* No cfg file => no sounds */
6524 if (!f)
6525 {
6526 if (show_sound_alloc)
6527 {
6528 fprintf(dbo, "** Can't open cfg file '%s'\n", buffer);
6529 fclose(dbo);
6530 }
6531 return;
6532 }
6533
6534 /* Parse the file */
6535 while (fgets(buffer, sizeof(buffer), f))
6536 {
6537 char *sample_name;
6538 int event_number;
6539
6540 /* Skip comments and lines that begin with whitespace */
6541 if (*buffer == '#' || isspace((unsigned char)*buffer))
6542 {
6543 continue;
6544 }
6545
6546 /* Hack: ignore any line beginning '[' (section marker) */
6547 if (*buffer == '[')
6548 {
6549 continue;
6550 }
6551
6552 /* Place a NULL after the event name and find the first sample name */
6553 sample_name = buffer;
6554 while (*sample_name && !isspace((unsigned char)*sample_name))
6555 sample_name++;
6556
6557 /* Bad line? */
6558 if (*sample_name == 0)
6559 {
6560 continue;
6561 } /* just ignore it */
6562
6563 /* Terminate the sample name */
6564 *sample_name++ = 0;
6565
6566 /* Look up the event name to get the event number */
6567 for (event_number = SOUND_MAX - 1; event_number >= 0; event_number--)
6568 if (!strcmp(buffer, angband_sound_name[event_number]))
6569 break;
6570
6571 /* No match -> just ignore the line */
6572 if (event_number < 0)
6573 {
6574 if (show_sound_alloc)
6575 fprintf(dbo, "* Ignoring unknown event '%s'\n", buffer);
6576 continue;
6577 }
6578
6579 /* Find the = */
6580 while (*sample_name && *sample_name != '=')
6581 sample_name++;
6582
6583 /* Bad line? */
6584 if (*sample_name == 0)
6585 {
6586 continue;
6587 } /* just ignore it */
6588
6589 /* Skip the '=' */
6590 sample_name++;
6591
6592
6593 /*
6594 | Now we find all the sample names and add them to the
6595 | appropriate list in the sample mapping array
6596 */
6597
6598 while (*sample_name)
6599 {
6600 char *s;
6601 SampNode *sn;
6602
6603 /* Find the start of the next word */
6604 while (isspace((unsigned char)*sample_name) && *sample_name)
6605 sample_name++;
6606
6607 /* End of line? */
6608 if (!*sample_name)
6609 {
6610 break;
6611 }
6612
6613 /* Find the end of the sample name */
6614 s = sample_name; /* start of the name */
6615 while (!isspace((unsigned char)*sample_name) && *sample_name)
6616 sample_name++;
6617
6618 /* Hack: shorten sample names that are too long */
6619 if ((sample_name - s) > max_sampname_len)
6620 s[max_sampname_len] = ' ';
6621
6622 /* Allocate a node in the sample list for the event */
6623 if ((sn = malloc(sizeof(SampNode))) == NULL)
6624 core("Out of memory (scanning sound.cfg)");
6625
6626 /* Link the node to the list */
6627 sn->next = sample[event_number].samplist;
6628 sample[event_number].samplist = sn;
6629
6630 /* Imcrement the sample count for that event */
6631 sample[event_number].samples++;
6632
6633 /*
6634 | Copy the sample name into the node, converting it into
6635 | RISC OS style as we go.
6636 */
6637 for (i = 0; !isspace((unsigned char)s[i]) && s[i]; i++)
6638 {
6639 if (s[i] == '.')
6640 sn->sample_name[i] = '/';
6641 else if (s[i] == '/')
6642 sn->sample_name[i] = '.';
6643 else
6644 sn->sample_name[i] = s[i];
6645 }
6646 /*
6647 | The sample name '*' is special and means "no new sound"
6648 | so don't store a filename for these mappings.
6649 */
6650 if (i == 1 && sn->sample_name[0] == '*')
6651 {
6652 i = 0;
6653 }
6654 sn->sample_name[i] = 0;
6655 }
6656 }
6657
6658 /* Close the file */
6659 fclose(f);
6660
6661 if (show_sound_alloc)
6662 {
6663 int i;
6664 SampNode *l;
6665
6666 for (i = 0; i < SOUND_MAX; i++)
6667 {
6668 fprintf(dbo, "\n\nEvent '%s'", angband_sound_name[i]);
6669 fprintf(dbo, " (%d sounds)\n", sample[i].samples);
6670 for (l = sample[i].samplist; l; l = l->next)
6671 fprintf(dbo, "\t%s\n", l->sample_name);
6672 }
6673 fclose(dbo);
6674 }
6675
6676 }
6677
6678
6679
6680 /*
6681 | Try to make sure that PlayIt is loaded.
6682 | This requires AngSound rel. 4
6683 */
check_playit(void)6684 static void check_playit(void)
6685 {
6686 if (SWI(2, 0, SWI_OS_Module, 18, "PlayIt"))
6687 {
6688 int t;
6689 SWI(2, 1, SWI_OS_File, 17, "Angsound:LoadPlayIt", &t);
6690 if (t == 1)
6691 SWI(1, 0, SWI_OS_CLI,
6692 "RMEnsure PlayIt 0.00 Run AngSound:LoadPlayIt");
6693 }
6694 }
6695
6696
6697
6698
initialise_sound(void)6699 static void initialise_sound(void)
6700 {
6701 /* Load the configuration file */
6702 Hourglass_On();
6703 read_sound_config();
6704 check_playit();
6705 Hourglass_Off();
6706 }
6707
6708
6709
play_sample(char * leafname)6710 static void play_sample(char *leafname)
6711 {
6712 char buffer[260];
6713
6714 strcpy(buffer, "%playit_stop");
6715
6716 if (!SWI(1, 0, SWI_OS_CLI, buffer))
6717 {
6718 SWI(1, 0, SWI_PlayIt_Volume, sound_volume);
6719 sprintf(buffer, "%%playit_play %sSound:%s", RISCOS_VARIANT, leafname);
6720 SWI(1, 0, SWI_OS_CLI, buffer);
6721 }
6722
6723 return;
6724 }
6725
6726
6727
play_sound(int event)6728 static void play_sound(int event)
6729 {
6730 /* Paranoia */
6731 if (!sound_initd)
6732 {
6733 return;
6734 }
6735
6736 /* Paranoia */
6737 if (event < 0 || event >= SOUND_MAX)
6738 return;
6739
6740 /* msg_format("Sound '%s'",angband_sound_name[event]); */
6741
6742 /* Choose a sample */
6743 if (sample[event].samples)
6744 {
6745 int s = rand() % sample[event].samples;
6746 SampNode *sn = sample[event].samplist;
6747 while (s--)
6748 {
6749 sn = sn->next;
6750 if (!sn)
6751 {
6752 plog("Adny botched the sound config - please send him a copy of your sound/cfg file.");
6753 }
6754 }
6755 if (*(sn->sample_name))
6756 play_sample(sn->sample_name);
6757 }
6758 }
6759
6760
6761
6762
6763 /*--------------------------------------------------------------------------*/
6764
6765
6766
6767 /*
6768 | Let the user change the alarm message
6769 */
do_alarm_message_input(int y)6770 static void do_alarm_message_input(int y)
6771 {
6772 int k;
6773 int inspos = strlen(alarm_message);
6774 char old_message[52];
6775
6776 strcpy(old_message, alarm_message);
6777
6778 do
6779 {
6780 put_fstr(26, y, CLR_YELLOW "%-51s", alarm_message);
6781 Term_gotoxy(26 + inspos, y);
6782 k = inkey();
6783 switch (k)
6784 {
6785 case 21: /* ^U */
6786 *alarm_message = 0;
6787 inspos = 0;
6788 break;
6789 case 128: case 8: /* delete */
6790 if (inspos > 0)
6791 {
6792 alarm_message[--inspos] = 0;
6793 }
6794 break;
6795 case 27: /* escape */
6796 strcpy(alarm_message, old_message);
6797 k = 13;
6798 break;
6799 default:
6800 if (k > 31 && k < 127 && inspos < 50)
6801 {
6802 alarm_message[inspos++] = k;
6803 alarm_message[inspos] = 0;
6804 }
6805 }
6806 }
6807 while (k != 13);
6808
6809 put_fstr(26, y, CLR_WHITE "%-51s", alarm_message);
6810 }
6811
6812
6813 #define tum_col(X) ((X) ? CLR_L_BLUE : CLR_WHITE )
6814 #define tum_onoff(X) ((X) ? "On " : "Off")
6815
Term_user_acn(int n)6816 static errr Term_user_acn(int n)
6817 {
6818 int cursor_state;
6819 int optn = 0;
6820 int k, adj;
6821 int redraw_mung = 0;
6822 int max_opt = 11;
6823 int alarm_modified = 0; /* Will be true if the alarm choices need to be (re)saved */
6824
6825 /*
6826 | Hack: let the desktop front end know that
6827 | the user menu is active...
6828 */
6829 user_menu_active = TRUE;
6830
6831
6832 /*
6833 | This is thanks to Norcroft CC... it seems to want
6834 | to set up FP regs nice and early and then relies
6835 | on them remaining constant over the function call.
6836 | The trouble is that we implicitly call Wimp_Poll
6837 | whilst waiting for a key press...
6838 */
6839 event_mask.data.keepfpregisters = 1;
6840
6841 /*
6842 | Hack: alarm type 1 /looks/ the same as type 3 but doesn't get
6843 | cancelled as a type 3 would. This allows alarms to go off and
6844 | be cancelled without affecting the alarm type whilst it's being
6845 | set up here.
6846 */
6847 if (alarm_type == 3)
6848 {
6849 alarm_type = 1;
6850 }
6851
6852 /*
6853 | Store the screen
6854 */
6855 Term_activate(&(data[0].t));
6856 Term_save();
6857 Term_get_cursor(&cursor_state);
6858 Term_set_cursor(TRUE);
6859
6860 do
6861 {
6862 redraw_mung = 0;
6863 Term_clear();
6864 put_fstr(2, 1, CLR_YELLOW "%s %s", VARIANT, VERSION);
6865 put_fstr(2, 2, CLR_SLATE "Front-end %s", PORTVERSION);
6866 put_fstr(2, 4, CLR_WHITE
6867 "Use cursor up/down to select an option then cursor left/right to alter it.");
6868 put_fstr(2, 5, CLR_WHITE
6869 "Hit 'S' to save these settings (alarm settings are saved automatically).");
6870 put_fstr(2, 6, CLR_WHITE "Hit ESC to return to the game.");
6871
6872 for (k = 0; k < 32; k++)
6873 {
6874 Term_putch(31 + k + (k / 2), 8, k / 2, '#');
6875 }
6876
6877 do
6878 {
6879 /* Gamma value never goes about 9.00, 5 char array should be fine */
6880 char gammas[5];
6881 sprintf(gammas, "%.2lf", gamma);
6882
6883 put_fstr(2, 8,
6884 "%s Gamma correction : %s", tum_col(optn == 0), gammas);
6885 put_fstr(2, 9, "%s Force monochrome : %s",
6886 tum_col(optn == 1), tum_onoff(force_mono));
6887 put_fstr(2, 10, "%s Sound effects : %s",
6888 tum_col(optn == 2), tum_onoff(enable_sound));
6889 put_fstr(2, 11, "%s Sound effect volume : ", tum_col(optn == 3));
6890 put_fstr(26, 11, "%s%-3d",
6891 sound_volume > 127 ? CLR_RED : tum_col(optn == 3),
6892 sound_volume);
6893 put_fstr(30, 11, "%s(127 = full volume)", tum_col(optn == 3));
6894 put_fstr(2, 12, "%s Start fullscreen : %s",
6895 tum_col(optn == 4), tum_onoff(start_fullscreen));
6896 put_fstr(30, 12,
6897 "%s(also selects fullscreen/desktop now)", tum_col(optn == 4));
6898 put_fstr(2, 13, "%s Use hourglass : %s",
6899 tum_col(optn == 5), tum_onoff(use_glass));
6900 put_fstr(2, 14,
6901 "%s'Hard' input flushing : %s", tum_col(optn == 6), tum_onoff(hack_flush));
6902
6903 put_fstr(7, 16, "%s Alarm type : %-20s",
6904 tum_col(optn == 7), alarm_types[alarm_type]);
6905 put_fstr(7, 17, CLR_WHITE " Time : ");
6906 put_fstr(26, 17, "%s%02d", tum_col(optn == 8), alarm_h);
6907 put_fstr(28, 17, CLR_WHITE, ":");
6908 put_fstr(29, 17, "%s%02d", tum_col(optn == 9), alarm_m);
6909 put_fstr(7, 18, "%s Message : %-51s",
6910 tum_col(optn == 10), alarm_message);
6911 put_fstr(7, 19, "%s Beep : %s",
6912 tum_col(optn == 11), tum_onoff(alarm_beep));
6913
6914 #ifdef FE_DEBUG_INFO
6915 put_fstr(2, 23, "%sShow debug info", tum_col(optn == 23));
6916 max_opt = 12;
6917 #endif
6918
6919 switch (optn)
6920 {
6921 case 12: Term_gotoxy(2, 23);
6922 break;
6923 case 11: Term_gotoxy(26, 19);
6924 break;
6925 case 10: Term_gotoxy(26, 18);
6926 break;
6927 case 9: Term_gotoxy(29, 17);
6928 break;
6929 case 8: Term_gotoxy(26, 17);
6930 break;
6931 case 7: Term_gotoxy(26, 16);
6932 break;
6933 default: Term_gotoxy(26, optn + 8);
6934 }
6935
6936 k = inkey();
6937 adj = (k == '4' || k == 'h') ? -1 : (k == '6' || k == 'l') ? 1 : 0;
6938
6939 switch (k)
6940 {
6941 case 18: /* Hack: force the screen to update */
6942 redraw_mung = 1;
6943 k = 27;
6944 break;
6945 case 's': case 'S':
6946 save_choices();
6947 put_fstr(2, 23, CLR_YELLOW "Options saved. ");
6948 Term_fresh();
6949 Term_xtra(TERM_XTRA_DELAY, 750);
6950 Term_erase(2, 23, 60);
6951 break;
6952 case '8': case 'k':
6953 if (--optn < 0)
6954 {
6955 optn = max_opt;
6956 }
6957 break;
6958 case '2': case 'j':
6959 if (++optn > max_opt)
6960 {
6961 optn = 0;
6962 }
6963 break;
6964 case 13: case 32: case 't': /* Allow return, space and t to toggle some options */
6965 case '4': case 'h':
6966 case '6': case 'l':
6967 {
6968 switch (optn)
6969 {
6970 case 0: /* Gamma correction */
6971 gamma += adj * 0.05;
6972 if (gamma > 9.00)
6973 {
6974 gamma = 9.00;
6975 }
6976 if (gamma < 0.05)
6977 {
6978 gamma = 0.05;
6979 }
6980 Term_xtra(TERM_XTRA_REACT, 0);
6981 #ifndef FULLSCREEN_ONLY
6982 set_gamma_window_state();
6983 #endif /* FULLSCREEN_ONLY */
6984 /* flush(); */
6985 Term_fresh();
6986 break;
6987 case 1: /* Force monochrome */
6988 force_mono = !force_mono;
6989 if (fullscreen_font)
6990 redraw_areaFS(0, 0, 80, 24);
6991 else
6992 Term_xtra(TERM_XTRA_REACT, 0);
6993 /* flush(); */
6994 Term_fresh();
6995 break;
6996 case 2: /* Sound enable / disable */
6997 enable_sound = !enable_sound;
6998 #ifndef FULLSCREEN_ONLY
6999 set_sound_window_state();
7000 #endif /* FULLSCREEN_ONLY */
7001 if (enable_sound)
7002 {
7003 initialise_sound();
7004 }
7005 break;
7006 case 3: /* Sound volume */
7007 sound_volume += adj;
7008 if (sound_volume < SOUND_VOL_MIN)
7009 sound_volume = SOUND_VOL_MIN;
7010 if (sound_volume > SOUND_VOL_MAX)
7011 sound_volume = SOUND_VOL_MAX;
7012 #ifndef FULLSCREEN_ONLY
7013 set_sound_window_state();
7014 #endif /* FULLSCREEN_ONLY */
7015 break;
7016 case 4: /* Start fullscreen */
7017 start_fullscreen = !start_fullscreen;
7018 if (start_fullscreen)
7019 enter_fullscreen_mode();
7020 else if (!minimise_memory)
7021 leave_fullscreen_mode();
7022 break;
7023 case 5: /* Start fullscreen */
7024 use_glass = !use_glass;
7025 if (!use_glass)
7026 {
7027 if (glass_on)
7028 {
7029 Hourglass_Off();
7030 }
7031 glass_on = 0;
7032 }
7033 break;
7034 case 6: /* hack flush */
7035 hack_flush = !hack_flush;
7036 break;
7037 case 7: /* Alarm on/off */
7038 alarm_type += adj;
7039 if (adj)
7040 {
7041 alarm_modified = 1;
7042 }
7043 if (alarm_type > 2)
7044 {
7045 alarm_type = 0;
7046 }
7047 if (alarm_type < 0)
7048 {
7049 alarm_type = 2;
7050 }
7051 if (!alarm_type && alarm_disp)
7052 {
7053 ack_alarm();
7054 } /* XXXXX Cancel an already active alarm? */
7055 break;
7056 case 8: /* Alarm hours */
7057 alarm_h += adj;
7058 if (adj)
7059 {
7060 alarm_modified = 1;
7061 }
7062 if (alarm_h < 0)
7063 {
7064 alarm_h += 24;
7065 }
7066 if (alarm_h > 23)
7067 {
7068 alarm_h -= 24;
7069 }
7070 if (alarm_disp)
7071 {
7072 ack_alarm();
7073 }
7074 break;
7075 case 9: /* Alarm minutes */
7076 alarm_m += adj;
7077 if (adj)
7078 {
7079 alarm_modified = 1;
7080 }
7081 if (alarm_m < 0)
7082 {
7083 alarm_m += 60;
7084 }
7085 if (alarm_m > 59)
7086 {
7087 alarm_m -= 60;
7088 }
7089 if (alarm_disp)
7090 {
7091 ack_alarm();
7092 }
7093 break;
7094 case 10:
7095 alarm_modified = 1;
7096 do_alarm_message_input(18);
7097 break;
7098 case 11:
7099 alarm_modified = 1;
7100 alarm_beep = !alarm_beep;
7101 break;
7102 case 12:
7103 show_debug_info();
7104 redraw_mung = 1;
7105 k = 27;
7106 break;
7107 }
7108 }
7109 }
7110 }
7111 while (k != 27);
7112 }
7113 while (redraw_mung);
7114
7115 /* Rehack the alarm type: */
7116 if (alarm_type == 1)
7117 {
7118 alarm_type = 3;
7119 }
7120
7121 if (alarm_modified)
7122 {
7123 write_alarm_choices();
7124 }
7125
7126 Term_set_cursor(cursor_state);
7127
7128 /* Restore the screen */
7129 Term_load();
7130
7131 /* Don't need to preserve FP regs any more */
7132 event_mask.data.keepfpregisters = 0;
7133
7134 /*
7135 | Hack: tell the desktop front end that we're done.
7136 */
7137 user_menu_active = FALSE;
7138
7139 return 0;
7140 }
7141
7142
7143
7144
7145 /*--------------------------------------------------------------------------*/
7146
7147 #ifdef USE_FILECACHE
7148
7149 /*
7150 | 'Random' File-cacheing for *band.
7151 |
7152 | Rewritten since as of Zang 225 the mechanism for handling
7153 | these files has changed dramatically and the old system
7154 | is no longer viable.
7155 |
7156 | These new functions basically provide an alternative to the
7157 | normal my_fopen() (or fopen()) and my_fgets() functions.
7158 |
7159 | To use the file caching it is therefore necessary to alter
7160 | files.c to call cached_fopen(), cached_fclose() and cached_fgets()
7161 | rather than the normal functions.
7162 |
7163 | Note that these funtions will only work for files that are intended
7164 | to be read as a series of \n terminated lines of ASCII text using my_fgets().
7165 |
7166 */
7167
7168 /*
7169 | Hack: use the game's dynamic area if possible:
7170 */
7171 #define fc_malloc(X) (g_malloc(X))
7172 #define fc_free(X) (g_free(X,0))
7173
7174 #ifndef ABBR_FILECACHE
7175 /*
7176 | Make these to do nothing. They'll never
7177 | be called anyway. Having them present makes
7178 | for neater code later on (ie. we use a variable
7179 | rather than the pre-processor to decide whether
7180 | to do compression).
7181 */
compress_string(char * os,char * s)7182 static int compress_string(char *os, char *s)
7183 {
7184 core("main-acn internal logic error 001");
7185 return 0;
7186 }
decompress_string(char * d,char * s,int max_len)7187 static int decompress_string(char *d, char *s, int max_len)
7188 {
7189 core("main-acn internal logic error 002");
7190 return 0;
7191 }
compressed_length(char * s)7192 static int compressed_length(char *s)
7193 {
7194 core("main-acn internal logic error 003");
7195 return 0;
7196 }
7197
7198 #else
7199
7200 /*
7201 | When caching files we try to use some abbreviations.
7202 | We use both whole words and pairs of letters.
7203 | NB: For this to work, the file must contain only
7204 | 7 bit characters.
7205 */
7206 static char *abbrv_w[] =
7207 {
7208 /* These words all begin with a space */
7209 " of ", " the ", " you ", " to ", " a ", " says", " is ", " that ", " and ",
7210 " your ", " are ", " it ", " be ", " for ", " me", " will ", " in ",
7211 " not ", " this ", " have ", " can ", " on ", " my ", " with ", " say ",
7212 " all", " by ", " get ", " but ", " just ", " die", " as ", " time ",
7213 " if ",
7214 " like ",
7215 /* These words do not */
7216 "I ", "The ", "You ", "They ", "It ", "don", 0
7217 };
7218
7219 /* Number of words */
7220 #define FC_ABBRV_NUMWORDS 41
7221
7222 /* Number of them that don't start with a space */
7223 #define FC_ABBRV_NONSPC 6
7224
7225 /*
7226 | NB: No letter pair may start with \0.
7227 */
7228 static char abbrv_lp[] =
7229 "e ttht s heiner aoure'\0, anonf sd y r ongofator.\0"
7230 "n arllstha wes m ieaisen bl yndtoo yometele d f hve"
7231 "ayuralitneelN: chig ilroassaseliti lraa otedbede 'ri" "..u nntno!'ee\0\0";
7232
7233
7234 /*
7235 | Compress the given string using the abbreviation tables above.
7236 | Returns compressed length *including* terminator (it may
7237 | be part of an abbreviation, you see...)
7238 | Note that we can compress the string in-place, ie. 'os' may be
7239 | the same as 's'.
7240 */
compress_string(char * os,char * s)7241 static int compress_string(char *os, char *s)
7242 {
7243 char *o, *f, *d;
7244 int i;
7245
7246 o = os;
7247
7248 while (*s)
7249 {
7250 int fw, lw;
7251 if (*s == ' ')
7252 {
7253 fw = 0;
7254 lw = FC_ABBRV_NUMWORDS - FC_ABBRV_NONSPC;
7255 }
7256 else
7257 {
7258 fw = FC_ABBRV_NUMWORDS - FC_ABBRV_NONSPC;
7259 lw = FC_ABBRV_NUMWORDS;
7260 }
7261 for (i = fw; i < lw; i++)
7262 {
7263 d = abbrv_w[i]; /* Word to check against */
7264 for (f = s; *f && *f == *d; f++, d++)
7265 ;
7266 if (*d == 0) /* Match? */
7267 {
7268 s = *f ? f : f - 1; /* Update string pointer */
7269 *o++ = 128 + i; /* store code */
7270 break; /* Quit looking for words */
7271 }
7272 }
7273
7274 /* Do we need to check the letter pairs? */
7275 if (i == lw)
7276 {
7277 for (i = 0; abbrv_lp[i]; i += 2)
7278 {
7279 if (s[0] == abbrv_lp[i] && s[1] == abbrv_lp[i + 1])
7280 {
7281 *o++ = 128 + FC_ABBRV_NUMWORDS + i / 2;
7282 /* NB: If the next character is the terminator then we're done. */
7283 if (!s[1])
7284 {
7285 return (o - os);
7286 }
7287 s += 2; /* Quit looking for letters */
7288 break;
7289 }
7290 }
7291 /* NB: This next check is only safe because no letter pair starts with a NULL */
7292 if (!abbrv_lp[i])
7293 *o++ = *s++;
7294 }
7295 }
7296
7297 /* Don't forget that terminator! */
7298 *o++ = 0;
7299
7300 return o - os;
7301 }
7302
7303 /*
7304 | As compress_string (above), but stores nothing and
7305 | only returns the length of the compressed string.
7306 */
compressed_length(char * s)7307 static int compressed_length(char *s)
7308 {
7309 char *f, *d;
7310 int i, l;
7311
7312 l = 0;
7313 while (*s)
7314 {
7315 int fw, lw;
7316 if (*s == ' ')
7317 {
7318 fw = 0;
7319 lw = FC_ABBRV_NUMWORDS - FC_ABBRV_NONSPC;
7320 }
7321 else
7322 {
7323 fw = FC_ABBRV_NUMWORDS - FC_ABBRV_NONSPC;
7324 lw = FC_ABBRV_NUMWORDS;
7325 }
7326 for (i = fw; i < lw; i++)
7327 {
7328 d = abbrv_w[i];
7329 for (f = s; *f && *f == *d; f++, d++)
7330 ;
7331 if (*d == 0) /* Match? */
7332 {
7333 s = *f ? f : f - 1; /* Update string pointer */
7334 l++; /* increment output length */
7335 break; /* Quit looking for words */
7336 }
7337 }
7338
7339 /* Do we need to check the letter pairs? */
7340 if (i == lw)
7341 {
7342 for (i = 0; abbrv_lp[i]; i += 2)
7343 {
7344 if (s[0] == abbrv_lp[i] && s[1] == abbrv_lp[i + 1])
7345 {
7346 l++; /* increment output length */
7347 /* NB: If the next character is the terminator then we're done. */
7348 if (!s[1])
7349 {
7350 return l;
7351 }
7352 s += 2; /* Quit looking for letters */
7353 break;
7354 }
7355 }
7356 /* NB: This next check is only safe because no letter pair starts with a NULL */
7357 if (!abbrv_lp[i])
7358 {
7359 l++;
7360 s++;
7361 }
7362 }
7363 }
7364 /* Don't forget that terminator! */
7365 return l + 1;
7366 }
7367
7368
7369
7370 /*
7371 | Decompress the given string 's' into the buffer at 'd'.
7372 | At most, max_len characters (incl. \0 terminator) will be
7373 | written into d.
7374 | Returns the length of 's'.
7375 */
decompress_string(char * d,char * s,int max_len)7376 static int decompress_string(char *d, char *s, int max_len)
7377 {
7378 char *os = s;
7379
7380 while (max_len > 1)
7381 {
7382 int nc = *s++; /* Get next character */
7383
7384 if (nc < 128) /* Is it a plain character? */
7385 {
7386 if (0 == (*d++ = nc))
7387 {
7388 break;
7389 }
7390 max_len--;
7391 }
7392 else /* Abbreviation to expand. */
7393 {
7394 if (nc >= FC_ABBRV_NUMWORDS + 128) /* Letter pair? */
7395 {
7396 *d++ = abbrv_lp[(nc - (FC_ABBRV_NUMWORDS + 128)) * 2];
7397 if (0 ==
7398 (*d++ = abbrv_lp[(nc - (FC_ABBRV_NUMWORDS + 128)) * 2 + 1]))
7399 break;
7400 max_len -= 2;
7401 }
7402 else /* It's a word */
7403 {
7404 char *ws = abbrv_w[nc - 128];
7405 while (*ws && max_len > 1)
7406 {
7407 *d++ = *ws++;
7408 max_len--;
7409 }
7410 }
7411 }
7412 }
7413
7414 /* Skip over the rest of the abbreviated string if we ran out of space */
7415 if (max_len <= 1) /* Out of space? */
7416 {
7417 int nc;
7418 *d = 0; /* Terminate */
7419 do
7420 {
7421 nc = *s++; /* Next char */
7422 if (nc >= 128 + FC_ABBRV_NUMWORDS) /* Ignore words */
7423 nc = abbrv_lp[(nc - (FC_ABBRV_NUMWORDS + 128) * 2) + 1]; /* Only check 2nd letter of pair */
7424 }
7425 while (nc);
7426 }
7427 return s - os; /* Length of abbreviated string */
7428 }
7429
7430 #endif /* ABBR_FILECACHE */
7431
7432
7433 /* Each entry in the cache looks like this: */
7434 typedef struct fce_
7435 {
7436 char *name; /* canonical pathname of file */
7437 char *text; /* text (be it compressed or not) */
7438 char *eof; /* byte beyond the last byte of text */
7439 int used; /* access counter when the file was last used */
7440 int compressed; /* compression method, (ie. 0 for none or 1 for abbreviations) */
7441 }
7442 FileCacheEntry;
7443
7444 /*
7445 | The handles we chuck around are pointers to one of these structs.
7446 | Note that since we actually return (and take) |FILE*|s we just
7447 | compare the value of a |FILE*| with the limits of the array of
7448 | |CachedFileHandle|s to decide whether its 'ours' or a genuine
7449 | (ie. stdio) file handle. This /is/ pretty lame, I know...
7450 */
7451 typedef struct cfh_
7452 {
7453 char *ptr; /* sequential file pointer, as it were */
7454 FileCacheEntry *fce; /* ->the file-cache entry data */
7455 }
7456 CachedFileHandle;
7457
7458 #define MAX_OPEN_CACHED_FILES 16 /* We allow up to 16 of these files open at once */
7459 #define MAX_CACHE_ENTRIES 64 /* We allow up to 64 cache entries */
7460
7461 static FileCacheEntry *file_cache; /* to be used as file_cache[MAX_CACHE_ENTRIES] */
7462 static CachedFileHandle *cached_file_handle; /* to be used as cached_file_handle[MAX_OPEN_CACHED_FILES] */
7463 static int file_cache_initd = 0; /* Is the cache initialised? */
7464 static int file_cache_size = 0; /* Total size of the cached files */
7465 static int fc_access_counter = 1; /* incremented on each cache access */
7466 /*
7467 | Pre-calculate max. possible value of a FILE* (ie. address in memory)
7468 | that could be a valid |CachedFileHandle*|.
7469 */
7470 static FILE *max_cfh_addr; /* == (FILE*) (&(cached_file_handle[MAX_OPEN_CACHED_FILES-1])) */
7471
7472 /*
7473 | Initialise the file cache
7474 */
init_file_cache(void)7475 static void init_file_cache(void)
7476 {
7477 int i;
7478
7479 /* Allocate storage */
7480 file_cache = fc_malloc(MAX_CACHE_ENTRIES * sizeof(FileCacheEntry));
7481 cached_file_handle =
7482 fc_malloc(MAX_OPEN_CACHED_FILES * sizeof(CachedFileHandle));
7483
7484 if (!file_cache || !cached_file_handle)
7485 {
7486 /* Disable file-caching */
7487 if (file_cache)
7488 {
7489 fc_free(file_cache);
7490 }
7491 if (cached_file_handle)
7492 {
7493 fc_free(cached_file_handle);
7494 }
7495 use_filecache = 0;
7496 }
7497 else
7498 {
7499 /* Initialise the cache */
7500 for (i = 0; i < MAX_CACHE_ENTRIES; i++)
7501 file_cache[i].name = NULL;
7502 for (i = 0; i < MAX_OPEN_CACHED_FILES; i++)
7503 cached_file_handle[i].fce = NULL;
7504 fc_access_counter = 1;
7505 file_cache_size = 0;
7506 max_cfh_addr =
7507 (FILE *)(&(cached_file_handle[MAX_OPEN_CACHED_FILES - 1]));
7508 }
7509 file_cache_initd = 1;
7510 }
7511
7512
7513 /*
7514 | Helper: take a copy of the string and return a pointer to it
7515 */
string_cpy(char * s)7516 static char *string_cpy(char *s)
7517 {
7518 char *d = fc_malloc(strlen(s) + 1L);
7519 if (d)
7520 {
7521 strcpy(d, s);
7522 }
7523 return d;
7524 }
7525
7526
7527 /*
7528 | Cache the specified file, returning either the cache entry
7529 | that it has been cached at, or NULL for failure.
7530 |
7531 | Note that for the abbreviated file cache a temporary file
7532 | is used to allow the compression to be applied just once.
7533 | (otherwise it has to be done twice - once to determine the
7534 | eventual compressed size and once to actually store and compress
7535 | it).
7536 */
cache_file(char * name)7537 static FileCacheEntry *cache_file(char *name)
7538 {
7539 int i, size = 0;
7540 FILE *fp;
7541 char buffer[1024];
7542 char *d;
7543
7544 FILE *tf = NULL; /* Used if abbr_filecache and abbr_tmpfile are set */
7545 char cfn[1024]; /* Used if abbr_filecache and abbr_tmpfile are set */
7546
7547 /* Find the first free slot in the cache */
7548 for (i = 0; i < MAX_CACHE_ENTRIES; i++)
7549 if (!file_cache[i].name)
7550 break;
7551
7552 /* No more entries? */
7553 if (i >= MAX_CACHE_ENTRIES)
7554 {
7555 return NULL;
7556 }
7557
7558 /* Set up the info on the file */
7559 if ((file_cache[i].name = string_cpy(name)) == NULL)
7560 {
7561 return NULL;
7562 }
7563
7564 /* Open the file */
7565 fp = my_fopen(name, "r");
7566 if (!fp)
7567 {
7568 fc_free(file_cache[i].name);
7569 file_cache[i].name = 0;
7570 return NULL;
7571 }
7572
7573 /* Open/create tempfile if need be: */
7574 if (abbr_filecache && abbr_tmpfile)
7575 {
7576 /* Hack: Form the pathname of the cached compressed file (in canonical form) */
7577 sprintf(cfn, "%s%s", scrap_path,
7578 riscosify_name(name + strlen(resource_path)));
7579 /* Ensure that that particular directory exists... */
7580 ensure_path(cfn);
7581 /* Check whether cache file is out of date */
7582 if (file_is_newer(riscosify_name(name), cfn))
7583 {
7584 tf = fopen(cfn, "wb");
7585 size = 0;
7586 }
7587 else
7588 {
7589 tf = fopen(cfn, "rb");
7590 if (tf)
7591 {
7592 size = myFile_Size(cfn);
7593 }
7594 }
7595 }
7596
7597 /* If we don't have the cached file (but want it), compress the source text to it */
7598 if (tf)
7599 {
7600 if (!size)
7601 {
7602 int k;
7603 while (!my_fgets(fp, buffer, sizeof(buffer)))
7604 {
7605 if (smart_filecache && (!*buffer || *buffer == '#'))
7606 continue;
7607 k = compress_string(buffer, buffer);
7608 if (fwrite(buffer, 1, k, tf) != k)
7609 {
7610 fclose(tf);
7611 remove(cfn);
7612 core("error writing tempfile");
7613 }
7614 size += k;
7615 }
7616 fclose(tf);
7617 tf = fopen(cfn, "rb");
7618 }
7619 }
7620 else
7621 {
7622 /* Count the number of bytes */
7623 while (!my_fgets(fp, buffer, sizeof(buffer)))
7624 {
7625 if (smart_filecache && (!*buffer || *buffer == '#'))
7626 continue;
7627 if (abbr_filecache)
7628 size += compressed_length(buffer);
7629 else
7630 size += strlen(buffer) + 1;
7631 }
7632 }
7633
7634 /* Close the (source) file */
7635 my_fclose(fp);
7636
7637 /* Allocate enough storage for the text */
7638 file_cache[i].text = fc_malloc(size + 1L);
7639 if (!file_cache[i].text)
7640 {
7641 fc_free(file_cache[i].name);
7642 file_cache[i].name = 0;
7643 if (tf)
7644 {
7645 fclose(tf);
7646 }
7647 return NULL;
7648 }
7649
7650 /* Do we have a tempfile to load? */
7651 if (tf)
7652 {
7653 if (fread(file_cache[i].text, 1, size, tf) != size)
7654 core("error reading tempfile");
7655 fclose(tf);
7656 }
7657 else
7658 {
7659 /* Re-open the file... */
7660 fp = my_fopen(name, "r");
7661 if (!fp)
7662 {
7663 fc_free(file_cache[i].name);
7664 fc_free(file_cache[i].text);
7665 file_cache[i].name = 0;
7666 return NULL;
7667 }
7668
7669 /* And read it into the buffer... */
7670 d = file_cache[i].text;
7671 while (!my_fgets(fp, buffer, sizeof(buffer)))
7672 {
7673 if (smart_filecache && (!*buffer || *buffer == '#'))
7674 continue;
7675 if (abbr_filecache)
7676 d += compress_string(d, buffer);
7677 else
7678 {
7679 strcpy(d, buffer);
7680 d += strlen(buffer) + 1;
7681 }
7682 }
7683
7684 if ((d - file_cache[i].text) != size)
7685 {
7686 debug("Calculated size is %d, pointer offset is %d", size,
7687 (d - file_cache[i].text));
7688 core("Cached file is larger than calculated!");
7689 }
7690
7691 /* Close the file */
7692 my_fclose(fp);
7693 }
7694
7695 /* Set up the 'last accessed' value, etc. */
7696 file_cache[i].used = fc_access_counter++;
7697 file_cache[i].eof = file_cache[i].text + size;
7698 file_cache[i].compressed = abbr_filecache;
7699 file_cache_size += size;
7700
7701 /* Return success */
7702 return &(file_cache[i]);
7703 }
7704
7705
7706 /*
7707 | Discard a file from the cache
7708 */
discard_cached_file(int i)7709 static void discard_cached_file(int i)
7710 {
7711 if (!file_cache[i].name)
7712 {
7713 return;
7714 } /* invalid request */
7715 fc_free(file_cache[i].text);
7716 fc_free(file_cache[i].name);
7717 file_cache_size -= (file_cache[i].eof) - (file_cache[i].text);
7718 file_cache[i].name = 0;
7719 }
7720
7721
7722 /*
7723 | Attempt to flush as much of the cache as required
7724 | to bring it within the size limit.
7725 | If protect != 0 then that entry in the cache won't be flushed.
7726 */
flush_file_cache(FileCacheEntry * protect)7727 static void flush_file_cache(FileCacheEntry * protect)
7728 {
7729 int i, j, done;
7730 int oldest_u, oldest_e;
7731 FileCacheEntry *fce;
7732 int needed = (4 << 10); /* Hack: try to free at least 4K */
7733
7734 done = (file_cache_size + needed) <= max_file_cache_size;
7735
7736 while (!done)
7737 {
7738 oldest_u = fc_access_counter;
7739 oldest_e = -1;
7740
7741 fce = file_cache;
7742 /* Find oldest entry that isn't in use */
7743 for (i = 0; i < MAX_CACHE_ENTRIES; fce++, i++)
7744 {
7745 if (fce == protect)
7746 {
7747 continue;
7748 } /* Hack ;) */
7749 if (fce->name) /* Is this cache slot full? */
7750 {
7751 for (j = 0; j < MAX_OPEN_CACHED_FILES; j++)
7752 if (cached_file_handle[j].fce == fce)
7753 break;
7754 if (j < MAX_OPEN_CACHED_FILES)
7755 continue; /* Cached file is still open */
7756 if (fce->used < oldest_u)
7757 {
7758 oldest_e = i;
7759 oldest_u = file_cache[i].used;
7760 }
7761 }
7762 }
7763
7764 if (oldest_e < 0)
7765 done = 1; /* We can flush nothing more */
7766 else
7767 {
7768 discard_cached_file(oldest_e);
7769 done = (file_cache_size + needed) <= max_file_cache_size;
7770 }
7771 }
7772 }
7773
7774
7775 /*
7776 | Locate the specified file within the cache.
7777 | Returns NULL if the file is not cached
7778 */
find_cached_file(char * name)7779 static FileCacheEntry *find_cached_file(char *name)
7780 {
7781 int i;
7782 FileCacheEntry *fce = file_cache;
7783
7784 for (i = 0; i < MAX_CACHE_ENTRIES; i++, fce++)
7785 {
7786 if (fce->name)
7787 if (streq(fce->name, name))
7788 return fce;
7789 }
7790 return NULL;
7791 }
7792
7793
7794
7795 /*--------------------------------------------------------------------------*/
7796 /* Externally visible file cache stuff */
7797 /*--------------------------------------------------------------------------*/
7798
7799 /*
7800 | Open a file...
7801 | Returns the file cache handle of the file, or NULL for failure.
7802 | Note that if mode is anything other than "r" the call defers to
7803 | my_fopen().
7804 |
7805 | NB: The returned handle is almost certainly *NOT* a |FILE*|
7806 | (although it may be if the cache cannot accomodate the file).
7807 |
7808 | Therefore, you *MUST* ensure that any file opened with cached_fopen()
7809 | is only ever accessed via cached_fgets() and cached_fclose().
7810 |
7811 | Failure to do so will result in, ahem, unpleasantness. Extreme
7812 | unpleasantness.
7813 */
cached_fopen(char * name,char * mode)7814 FILE *cached_fopen(char *name, char *mode)
7815 {
7816 FileCacheEntry *fcs = NULL;
7817 int fch;
7818
7819 if (strcmp(mode, "r") || !use_filecache)
7820 return my_fopen(name, mode);
7821
7822 if (!file_cache_initd)
7823 {
7824 init_file_cache();
7825 }
7826
7827 if (max_file_cache_size >= 0)
7828 {
7829 /* Find a free cache entry */
7830 for (fch = 0; fch < MAX_OPEN_CACHED_FILES; fch++)
7831 if (!cached_file_handle[fch].fce)
7832 break;
7833
7834 /* Out of handles? */
7835 if (fch >= MAX_OPEN_CACHED_FILES)
7836 return my_fopen(name, mode);
7837
7838 /* Is the file already cached? */
7839 fcs = find_cached_file(name);
7840 if (!fcs)
7841 {
7842 /* File wasn't cached, so cache it */
7843 flush_file_cache(NULL); /* Clean stuff out of the cache if need be */
7844 fcs = cache_file(name); /* Cache the new file */
7845 flush_file_cache(fcs); /* Flush, but keep the latest file */
7846 }
7847 }
7848
7849 /* Did we fail to cache the file? */
7850 if (!fcs)
7851 {
7852 return my_fopen(name, mode);
7853 }
7854
7855 /* File was cached OK */
7856 cached_file_handle[fch].ptr = fcs->text; /* Init sequential pointer */
7857 cached_file_handle[fch].fce = fcs; /* Cache block pointer */
7858 fcs->used = fc_access_counter++; /* Opening the file counts as an access */
7859
7860 return (FILE *)(&cached_file_handle[fch]);
7861 }
7862
7863
7864 /*
7865 | Close a file
7866 */
cached_fclose(FILE * fch_)7867 errr cached_fclose(FILE *fch_)
7868 {
7869 CachedFileHandle *fch;
7870
7871 /* Is the FILE* genuine? */
7872 if ((fch_ < (FILE *)cached_file_handle) || (fch_ > max_cfh_addr))
7873 return my_fclose(fch_);
7874
7875 fch = (CachedFileHandle *) fch_;
7876
7877 /* Check for "Ooopses": */
7878 if (fch->fce == NULL)
7879 core("cached_fclose called on a non-open file handle");
7880
7881 flush_file_cache(NULL); /* Clean out the cache if need be */
7882 fch->fce = NULL; /* Mark file handle as inactive */
7883
7884 return 0;
7885 }
7886
7887
7888 /*
7889 | Do the my_fgets thing on a file
7890 */
cached_fgets(FILE * fch_,char * buffer,int max_len)7891 errr cached_fgets(FILE *fch_, char *buffer, int max_len)
7892 {
7893 CachedFileHandle *fch;
7894 char *eof;
7895 char *ptr;
7896
7897 /* Is the FILE* genuine? */
7898 if ((fch_ < (FILE *)cached_file_handle) || (fch_ > max_cfh_addr))
7899 return my_fgets(fch_, buffer, max_len);
7900
7901 fch = (CachedFileHandle *) fch_;
7902
7903 /* Check for "Oopses": */
7904 if (!file_cache_initd)
7905 core("cached_fgets() on uninitialised file-cache");
7906 if (!fch->fce)
7907 core("cached_fgets called for a un-open file");
7908
7909 eof = fch->fce->eof;
7910 ptr = fch->ptr;
7911
7912 /* Out of bounds? */
7913 if (ptr >= eof)
7914 {
7915 return 1;
7916 } /* Read failed */
7917
7918 /*
7919 | Read the next line, up to \0 (which would have v=been \n in the original file),
7920 | or max_len-1 characters
7921 */
7922 if (fch->fce->compressed)
7923 ptr += decompress_string(buffer, ptr, max_len);
7924 else
7925 {
7926 if (eof - ptr < max_len)
7927 {
7928 max_len = eof - ptr;
7929 }
7930 for (; max_len >= 1; max_len--)
7931 if ((*buffer++ = *ptr++) == 0)
7932 break;
7933 *buffer = 0; /* terminate (paranoia) */
7934 }
7935
7936 /* Update sequential pointer */
7937 fch->ptr = ptr;
7938
7939 return 0;
7940 }
7941
7942 #endif /* USE_FILECACHE */
7943
7944
7945 /*
7946 | This section deals with checking that the .raw files are up to date
7947 | wrt to the .txt files. Note that this function won't work for RISC OS 2
7948 | (due to the lack of OS_Args 7) so it simply returns 0 to indicate that
7949 | the file isn't OOD.
7950 |
7951 | For this to work, the equivalent function (in init2.c) needs to be
7952 | #if-d out (and this function should be declared). You'll probably
7953 | also need to zap the UNIX #includes at the top of the file
7954 */
7955
check_modification_date(int fd,cptr template_file)7956 extern errr check_modification_date(int fd, cptr template_file)
7957 {
7958 char raw_buf[1024];
7959 char txt_buf[1024];
7960 int i;
7961 os_error *e;
7962
7963 if (os_version() < 300)
7964 {
7965 return 0;
7966 }
7967
7968 /* Use OS_Args 7 to find out the pathname 'fd' refers to */
7969 e = SWI(6, 0, SWI_OS_Args,
7970 /* In: */
7971 7, /* Get path from filehandle */
7972 fd, /* file handle */
7973 raw_buf, /* buffer */
7974 0, 0, /* unused */
7975 1024 /* size of buffer */
7976 /* No output regs used */
7977 );
7978 if (e)
7979 {
7980 core(e->errmess);
7981 }
7982
7983 /* Build the path to the template_file */
7984 path_make(txt_buf, ANGBAND_DIR_EDIT, template_file);
7985
7986 i = file_is_newer(riscosify_name(txt_buf), raw_buf);
7987
7988 return i;
7989 }
7990
7991
7992 /*--------------------------------------------------------------------------*/
7993
7994 /*
7995 | This is the hideous IClear hack. Basically what we do is to take a copy
7996 | of the module and kill it in the RMA. Then, on return to the desktop
7997 | we reinstate the module.
7998 |
7999 | NB: This is truly, truly evil.
8000 */
8001
8002 static int *iclear_module = NULL;
8003
8004 /*
8005 | Start the IClear hack
8006 */
iclear_hack(void)8007 static void iclear_hack(void)
8008 {
8009 os_error *e;
8010 int code = 0;
8011 int *i;
8012
8013 /* Get base address of module */
8014 e = SWI(2, 4, SWI_OS_Module, 18, "IClear", 0, 0, 0, &code);
8015 if (e || !code)
8016 return;
8017
8018 /* Module size is at code!-4 */
8019 i = (int *)code;
8020 iclear_module = malloc(i[-1] + 4);
8021 if (!iclear_module)
8022 return;
8023
8024 /* Copy the module */
8025 *iclear_module = i[-1];
8026 memcpy(iclear_module + 1, (void *)code, i[-1]);
8027
8028 /* Kill the current version */
8029 e = SWI(2, 0, SWI_OS_Module, 4, "IClear");
8030 if (e)
8031 {
8032 free(iclear_module);
8033 iclear_module = NULL;
8034 }
8035 }
8036
8037
8038 /*
8039 | Remove the IClear hack
8040 */
remove_iclear_hack(void)8041 static void remove_iclear_hack(void)
8042 {
8043 os_error *e;
8044
8045 if (!iclear_module)
8046 return;
8047
8048 e = SWI(3, 0, SWI_OS_Module, 11, iclear_module + 1, *iclear_module);
8049 if (e)
8050 debug("Failed to reinstall IClear: %s", e->errmess);
8051
8052 free(iclear_module);
8053 iclear_module = NULL;
8054 }
8055
8056
8057
8058 /*--------------------------------------------------------------------------*/
8059
8060 /* Alarm functions */
8061 static int alarm_ackd = 0; /* has the alarm been acknowledged? */
8062 static window_handle aw = 0; /* alarm window */
8063
8064 /*
8065 | Is the alarm due to go off, ie. is it enabled, and if so
8066 | does the current time match the alarm time?
8067 */
check_alarm()8068 static void check_alarm()
8069 {
8070 time_t t;
8071 struct tm *lt;
8072
8073 alarm_lastcheck = Time_Monotonic();
8074
8075 time(&t);
8076 lt = localtime(&t);
8077 if (lt->tm_hour == alarm_h && lt->tm_min == alarm_m)
8078 {
8079 if (!alarm_ackd) alarm_disp = 1;
8080 }
8081 else
8082 {
8083 alarm_ackd = 0;
8084 }
8085
8086 /* Hack: if the alarm has already been acknowledged then don't re-trigger it */
8087 if (alarm_ackd)
8088 {
8089 alarm_disp = 0;
8090 }
8091
8092 /* Hack: if the alarm should make a noise, then make one: */
8093 if (alarm_disp && alarm_beep == 1)
8094 {
8095 static unsigned int last_beep = 0;
8096 unsigned int t = Time_Monotonic();
8097 if (t > last_beep + 100)
8098 {
8099 Sound_SysBeep();
8100 last_beep = t;
8101 }
8102 }
8103
8104 /*
8105 | If we're in the desktop then fire the alarm off if need be.
8106 | If we aren't then do nothing - the fullscreen bored() function
8107 | will take care of the alarm.
8108 */
8109 #ifndef FULLSCREEN_ONLY
8110 if (!fullscreen_font && alarm_disp)
8111 trigger_alarm_desktop();
8112 #endif /* FULLSCREEN_ONLY */
8113 }
8114
8115
ack_alarm(void)8116 static void ack_alarm(void)
8117 {
8118 if (aw)
8119 {
8120 Window_Delete(aw);
8121 aw = 0;
8122 }
8123 alarm_ackd = 1;
8124 alarm_disp = 0;
8125
8126 if (alarm_type == 3)
8127 {
8128 /* One shot alarm */
8129 alarm_type = 0;
8130 write_alarm_choices();
8131 }
8132
8133 }
8134
8135 #ifndef FULLSCREEN_ONLY
8136 /*
8137 | Click in the (desktop) alarm window
8138 */
Hnd_AlarmClick(event_pollblock * pb,void * ref)8139 static BOOL Hnd_AlarmClick(event_pollblock * pb, void *ref)
8140 {
8141 ack_alarm();
8142 return TRUE;
8143 }
8144
8145
8146 /*
8147 | The alarm has gone off in the desktop
8148 */
trigger_alarm_desktop(void)8149 static void trigger_alarm_desktop(void)
8150 {
8151 char buffer[120];
8152 if (aw)
8153 return;
8154
8155 aw = Window_Create("alarm", template_TITLEMIN);
8156 if (!aw)
8157 {
8158 core("failed to create Alarm window!");
8159 }
8160 sprintf(buffer, "Alarm from %s", VARIANT);
8161 Window_SetTitle(aw, buffer);
8162 Event_Claim(event_CLICK, aw, 0, Hnd_AlarmClick, NULL);
8163 Event_Claim(event_CLOSE, aw, event_ANY, Hnd_AlarmClick, NULL);
8164
8165 Icon_printf(aw, 1, "An alarm was set for %02d:%02d", alarm_h, alarm_m);
8166 Icon_SetText(aw, 2, alarm_message);
8167 Window_Show(aw, open_CENTERED);
8168 }
8169
8170 #endif /* FULLSCREEN_ONLY */
8171
8172
8173 /*--------------------------------------------------------------------------*/
8174
8175 #ifndef FE_DEBUG_INFO
show_debug_info(void)8176 static void show_debug_info(void)
8177 {
8178 core("main-acn internal logic error 004");
8179 }
8180 #else
8181
8182 static int debug_cx = 0;
8183 static int debug_cy = 0;
8184 static int debug_cl = TERM_WHITE;
8185 static int debug_sl = 0;
8186
8187
debug_cls(void)8188 static void debug_cls(void)
8189 {
8190 Term_clear();
8191 debug_cx = debug_cy = debug_sl = 0;
8192 }
8193
debug_tcol(int c)8194 static void debug_tcol(int c)
8195 {
8196 debug_cl = c;
8197 }
8198
8199
debug_scroll(void)8200 static void debug_scroll(void)
8201 {
8202 char **c = ((term_data *)Term)->t.scr->c; /* char array [24][80] */
8203 byte **a = ((term_data *)Term)->t.scr->a; /* attr array [24][80] */
8204 int cc;
8205 char tmp[82];
8206 int y, x, p;
8207
8208 cc = a[1][0];
8209
8210 for (y = 1; y < 23; y++)
8211 {
8212 Term_gotoxy(0, y - 1);
8213
8214 for (x = p = 0; x < 80; x++)
8215 {
8216 Term_addch(a[y][x], c[y][x]);
8217 }
8218 }
8219
8220 Term_erase(0, 22, 80);
8221 }
8222
8223
debug_print_line(char * l)8224 static void debug_print_line(char *l)
8225 {
8226 char *le;
8227 int cr = 0;
8228
8229 /* Handle scrolling */
8230 if (debug_cy > 22)
8231 {
8232 debug_cy = 22;
8233 if (--debug_sl < 0)
8234 {
8235 int k;
8236 put_fstr(0, 23, CLR_YELLOW "[RET one line, SPC one page]");
8237 do
8238 {
8239 k = inkey();
8240 }
8241 while (k != 32 && k != 13);
8242 Term_erase(0, 23, 79);
8243 debug_sl = k == 32 ? 21 : 0;
8244 }
8245 debug_scroll();
8246 }
8247
8248 /* Hack: check for NL */
8249 for (le = l; *le; le++)
8250 if (*le == '\n')
8251 {
8252 cr = 1;
8253 break;
8254 }
8255
8256 /* display text */
8257 put_fstr(debug_cx, debug_cy, "$%c%.*s", 'A' + debug_cl, l);
8258
8259 /* move cursor */
8260 if (!cr)
8261 {
8262 debug_cx += (le - l);
8263 if (debug_cx >= 80)
8264 {
8265 cr = 1;
8266 }
8267 }
8268 if (cr)
8269 {
8270 debug_cx = 0;
8271 debug_cy += 1;
8272 }
8273
8274 Term_gotoxy(debug_cx, debug_cy);
8275
8276 }
8277
8278
debug_next_line(char * lb,char ** t,int cx)8279 static int debug_next_line(char *lb, char **t, int cx)
8280 {
8281 int i = 0;
8282 char *lt = *t;
8283
8284 if (!*lt)
8285 {
8286 return -1;
8287 } /* Out of text */
8288
8289 while (*lt && cx < 80)
8290 {
8291 lb[i] = *lt++;
8292
8293 if (lb[i] == '\n') /* New line */
8294 {
8295 cx = 0; /* Cursor x will be 0 after displaying */
8296 i++; /* Keep the \n in the output */
8297 break; /* All done */
8298 }
8299 else if (lb[i] == '\t') /* Tab */
8300 {
8301 while (cx < 80)
8302 {
8303 lb[i++] = ' ';
8304 cx++;
8305 if ((cx & 7) == 0)
8306 {
8307 break;
8308 }
8309 }
8310 }
8311 else /* Anything else */
8312 {
8313 cx++;
8314 i++;
8315 }
8316 }
8317
8318 lb[i] = 0; /* terminate line buffer */
8319 *t = lt; /* update text pointer */
8320 return cx; /* return cursor x after printing */
8321 }
8322
debug_printf(char * fmt,...)8323 static void debug_printf(char *fmt, ...)
8324 {
8325 char buffer[1024];
8326 char line[82];
8327 va_list ap;
8328 char *p = buffer;
8329
8330 va_start(ap, fmt);
8331 vsprintf(buffer, fmt, ap);
8332 va_end(ap);
8333
8334 /* Now split the string into display lines */
8335 while (debug_next_line(line, &p, debug_cx) >= 0)
8336 debug_print_line(line);
8337 }
8338
8339
debug_version_info(void)8340 static void debug_version_info(void)
8341 {
8342 debug_tcol(TERM_YELLOW);
8343
8344 debug_printf("\n\nMisc. Info:\n");
8345 debug_tcol(TERM_WHITE);
8346 debug_printf("\tVariant name = \"%s\"\n", VARIANT);
8347 debug_printf("\tFront-end version: %s\n", PORTVERSION);
8348 debug_printf("\tFront-end compiled: %s %s\n", __TIME__, __DATE__);
8349 debug_printf("\tCompile time flags:\n");
8350
8351 #ifdef USE_FILECACHE
8352 debug_printf("\t\tUSE_FILECACHE\n");
8353 #endif
8354
8355 #ifdef ABBR_FILECACHE
8356 debug_printf("\t\tABBR_FILECACHE\n");
8357 #endif
8358
8359 #ifdef SMART_FILECACHE
8360 debug_printf("\t\tSMART_FILECACHE\n");
8361 #endif
8362
8363 debug_tcol(TERM_YELLOW);
8364 debug_printf("\nResource path:\n");
8365 debug_tcol(TERM_WHITE);
8366 debug_printf("\t\"%s\"\n", resource_path);
8367
8368 debug_tcol(TERM_YELLOW);
8369 debug_printf("\nTempfile path:\n");
8370 debug_tcol(TERM_WHITE);
8371 debug_printf("\t\"%s\"\n", scrap_path);
8372 debug_printf("\tScrapfiles are %s deleted at exit.\n",
8373 (flush_scrap ? "" : "NOT"));
8374
8375 debug_tcol(TERM_YELLOW);
8376 debug_printf("\nChoices files:\n");
8377 debug_tcol(TERM_L_BLUE);
8378 debug_printf("\tDesired files:\n");
8379 debug_tcol(TERM_WHITE);
8380 debug_printf("\tPrimary (r/w): \"%s\"\n", choices_file[CHFILE_WRITE]);
8381 debug_printf("\t Fallback (r): \"%s\"\n", choices_file[CHFILE_READ]);
8382 debug_printf("\t Mirror (r/w): \"%s\"\n", choices_file[CHFILE_MIRROR]);
8383 debug_tcol(TERM_L_BLUE);
8384 debug_printf("\tActual files:\n");
8385 debug_tcol(TERM_WHITE);
8386 debug_printf("\t Write: \"%s\"\n", find_choices(TRUE));
8387 debug_printf("\t Read: \"%s\"\n", find_choices(FALSE));
8388
8389 debug_tcol(TERM_YELLOW);
8390 debug_printf("\nAlarm files:\n");
8391 debug_tcol(TERM_L_BLUE);
8392 debug_printf("\tDesired files:\n");
8393 debug_tcol(TERM_WHITE);
8394 debug_printf("\tPrimary (r/w): \"%s\"\n", alarm_file[CHFILE_WRITE]);
8395 debug_printf("\t Fallback (r): \"%s\"\n", alarm_file[CHFILE_READ]);
8396 debug_tcol(TERM_L_BLUE);
8397 debug_printf("\tActual files:\n");
8398 debug_tcol(TERM_WHITE);
8399 debug_printf("\t Write: \"%s\"\n", find_alarmfile(TRUE));
8400 debug_printf("\t Read: \"%s\"\n", find_alarmfile(FALSE));
8401 #ifdef USE_DA
8402 debug_tcol(TERM_YELLOW);
8403 debug_printf("\nDynamic areas:\n");
8404 debug_tcol(TERM_WHITE);
8405 debug_printf("\tFontcache DA = %d\t", font_area);
8406 debug_printf("size = %d\theap size = %d\n", font_area_size, font_heap_size);
8407 debug_printf("\t ralloc DA = %d\t", game_area);
8408 debug_printf("size = %d\theap size = %d\n", game_area_size, game_heap_size);
8409 #endif
8410 }
8411
8412
debug_filecache_info(void)8413 static void debug_filecache_info(void)
8414 {
8415 #ifndef USE_FILECACHE
8416 debug_tcol(TERM_L_DARK);
8417 debug_printf("File cache disabled at compile time.\n");
8418 #else
8419 int j, k;
8420 int t, cs, ucs, cf;
8421
8422 cf = cs = ucs = j = k = 0; /* To stop an usused warning if USE_FILECACHE is undefined */
8423 t = strlen(resource_path);
8424
8425 if (!file_cache_initd)
8426 {
8427 init_file_cache();
8428 } /* Paranoia */
8429 debug_tcol(TERM_YELLOW);
8430 debug_printf("\nFilecache contents:\n");
8431 debug_tcol(TERM_L_BLUE);
8432 debug_printf("Flags: Smart=%d; Abbrv=%d; Slave=%d; Enable=%d\n",
8433 smart_filecache, abbr_filecache, abbr_tmpfile, use_filecache);
8434 debug_tcol(TERM_SLATE);
8435 if (smart_filecache || abbr_filecache)
8436 debug_printf("\t\t%3s %6s/%-6s %6s %6s Path (relative to lib/)\n",
8437 "Hnd", "Cache", "Disc", "Time", "Status");
8438 else
8439 debug_printf("\t\t%3s %6s %6s %6s Path (relative to lib/)\n", "Hnd",
8440 "Size", "Time", "Status");
8441
8442 for (j = 0; j < MAX_CACHE_ENTRIES; j++)
8443 {
8444 FileCacheEntry *fce = &(file_cache[j]);
8445 if (fce->name)
8446 {
8447 cf++;
8448 debug_tcol(TERM_L_GREEN);
8449 debug_printf("\t\t%3d ", j);
8450 debug_tcol(TERM_L_UMBER);
8451 if (!smart_filecache && !abbr_filecache)
8452 debug_printf("%6d ", fce->eof - fce->text);
8453 else
8454 {
8455 debug_printf("%6d/", fce->eof - fce->text);
8456 k = myFile_Size(riscosify_name(fce->name));
8457 debug_printf("%-6d ", k);
8458 if (k > 0)
8459 {
8460 ucs += k;
8461 }
8462 }
8463 cs += fce->eof - fce->text;
8464 debug_printf("%6d ", fce->used);
8465 for (k = 0; k < MAX_OPEN_CACHED_FILES; k++)
8466 if (cached_file_handle[k].fce == fce)
8467 break;
8468 debug_tcol(TERM_RED);
8469 debug_printf("%-6s ", k < MAX_OPEN_CACHED_FILES ? "Open" : "");
8470 debug_tcol(TERM_L_UMBER);
8471 debug_printf("%s\n", fce->name + t);
8472 }
8473 }
8474
8475 debug_tcol(TERM_L_BLUE);
8476 debug_printf("\tTotal:\t%3d ", cf);
8477 if (ucs)
8478 debug_printf("%6d/%-6d\n", cs, ucs);
8479 else
8480 debug_printf("%6d\n", cs);
8481 debug_tcol(TERM_BLUE);
8482 #endif /* USE_FILECACHE */
8483 }
8484
8485
show_debug_info(void)8486 static void show_debug_info(void)
8487 {
8488 int k;
8489 /* blank the term */
8490 debug_cls();
8491
8492 /* Repeatedly prompt for a command */
8493 do
8494 {
8495 debug_tcol(TERM_VIOLET);
8496 debug_printf("\nInfo: (V)ersion, (F)ilecache, ESC=exit ");
8497 do
8498 {
8499 k = inkey();
8500 switch (k)
8501 {
8502 case 'v': case 'V': debug_version_info();
8503 break;
8504 case 'f': case 'F': debug_filecache_info
8505 ();
8506 break;
8507 case 27: break;
8508 default: k = 0;
8509 }
8510 }
8511 while (!k);
8512 }
8513 while (k != 27);
8514
8515 Term_clear();
8516 }
8517
8518 #endif /* FE_DEBUG_INFO */
8519
8520 #endif /* __riscos */
8521
8522
8523