3 * Purpose: Support for RISC OS versions of Angband
5 * Copyright (c) 2000-2007 Musus Umbra, Antony Sidwell, Thomas Harris,
6 * Andrew Sidwell, Ben Harrison.
8 * This work is free software; you can redistribute it and/or modify it
9 * under the terms of either:
11 * a) the GNU General Public License as published by the Free Software
12 * Foundation, version 2, or
14 * b) the "Angband licence":
15 * This software may be copied and distributed for educational, research,
16 * and not for profit purposes provided that this copyright and statement
17 * are included in all such copies. Other copyrights may also apply.
25 * Purpose: Support for RISC OS Angband 2.9.x onwards (and variants)
26 * Current maintainer: Antony Sidwell <antony@isparp.co.uk> (ajps)
28 * NB: This code is still under continuous development - if you want to use
29 * it for your own compilation/variant, please contact me so that I can
30 * keep you up to date and give you support :)
32 * NB: This frontend will no longer work as-is for modern Zangbands (2.7.3
33 * onwards), as the display code has changed, and so our platform-specific
34 * menu needs adjusting to use the appropriate new functions. A version which
35 * should work should be supplied with the Z source. -- ajps
37 * NB: This frontend will not work with the in-development ToME3, as the file
38 * handling (and many other parts) have been completely overhauled. I suspect
39 * it is not worth trying to shoehorn that model into this code, and a fresh,
40 * UNIX-porting-tools approach may be better suited. -- ajps
42 * Prerequisites to compiling:
44 * DeskLib 2.50 or later
46 * An ANSI C compiler (tested with Acorn's C/C++ and GCC, but should be OK
47 * with any decent compiler)
49 * My binary distribution (for the templates and other bits)
52 * The following symbols are *required* and *must* be defined properly.
57 * This is the port version; it appears in the infobox.
59 #define PORTVERSION "1.34 (2007-06-24)"
63 * These two get variant and version data from Angband itself; older
64 * variants may not have these defined and will have to be altered.
67 #define VARIANT VERSION_NAME
71 #define VERSION VERSION_STRING
76 * This must match the entry in the !Variant Obey file, and it must only
77 * contain characters that are valid as part of a RISC OS path variable.
78 * [eg. "Yin-Yangband" is not okay, "EyAngband" is.]
80 #ifndef RISCOS_VARIANT
81 #define RISCOS_VARIANT "Angband"
86 * For the info box. [eg. "Ben Harrison"]
89 #define AUTHORS "Robert Ruehlmann"
94 * For the info box. [eg. "Musus Umbra"]
97 #define PORTERS "Antony Sidwell"
102 * Iconbar icon sprite name eg. "!angband". Note that this must be a valid
103 * sprite name; it may need modifying for long variant names.
106 #define ICONNAME "!"RISCOS_VARIANT
111 * This should expand to an expression that is true if the player is dead.
112 * Examples (correct as of Feb 2004):
113 * Vanilla (and most variants): #define PDEADCHK (p_ptr->is_dead)
114 * Zangband: #define PDEADCHK (p_ptr->state.is_dead)
115 * Tome: #define PDEADCHK (!alive)
116 * SCthAngband: #define PDEADCHK (!alive || death)
119 #define PDEADCHK (p_ptr->is_dead)
124 * This defines which of the various sets of memory allocation prototypes
125 * should be used for this variant.
127 * 1: The pre 2.9.x type, where g_free returns an errr (largely obsolete)
128 * 2: The 2.9.x type, where sizes are type "huge" and g_free takes a size.
129 * 3: The 2.9.7(ish)+ type, where they take sizes as size_t
137 * Many of the variants based on older Angbands use huge rather than
138 * size_t in the fd_* functions. There are other halfway changes too,
139 * so you have to pick one of three for each variant. :(
146 * HAS_MY_STRCPY, HAS_MY_STRCAT, HAS_MY_STRNICMP
147 * We require the definition of two functions: my_strcat and my_strcpy.
148 * Some variants already have these defined (e.g. modern Vanilla), and
149 * so these should be defined when compiling those.
152 #define HAS_MY_STRCPY
153 #define HAS_MY_STRCAT
154 #define HAS_MY_STRNICMP
159 * This should be TRUE if the variant actually supports bigscreen, FALSE
163 #define BIGSCREEN FALSE
168 * In case someone's removed the core() function in an attempt
169 * to clean up the code but just making work for people with no
176 * If defined, it enables the use of dynamic areas (these are still only
177 * used when the !Variant file allows it). It is likely that this option
178 * will eventually be removed altogether as there is no major advantege
179 * to using DAs over just using the Wimpslot.
185 * If defined, the Wimp window-based interface will be disabled, and the
186 * game will only play in fullscreen mode. This turns out to be a pointless
187 * feature, as the memory saving is now negligable compared to the overall
190 /* #define FULLSCREEN_ONLY */
193 * ZANGBAND_TERM_PACKAGE
194 * New version of Zangband (2.7.3ish and later) use a new term streamlined
195 * term package including a put_fstr function we have to use for our
196 * "platform specific menu" in the game. Define this if you are compiling
197 * such a version of Zangband or (who knows?) a variant.
199 /* #define ZANGBAND_TERM_PACKAGE */
203 * The following symbols control the (optional) file-cache:
204 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
205 * NOTE (11th Dec 2004): The file caches have not been used for the last
206 * few years - I do not believe they still work with most variants, except
207 * possibly some branched off old Zangband (e.g. Cth). The introduction of
208 * scripting into those variants which used to use large plain text files
209 * seems to have diminished their usefulness. -- Antony Sidwell
211 * NB: Variants that don't repeatedly read any files whilst running
212 * (eg. vanilla, sang, etc) should NOT define USE_FILECACHE, etc. as
213 * it causes a non-negligable amount of code to be compiled in.
215 * NB: The file-cache functions require that some code in files.c is modified
216 * to use the cached_* functions. This should be utterly trivial.
218 * NB: The returned handle from cached_fopen() is almost certainly *NOT*
219 * a |FILE*| (although it may be if the cache cannot accomodate the file).
221 * Therefore, you *MUST* ensure that any file opened with cached_fopen()
222 * is only ever accessed via cached_fgets() and cached_fclose().
224 * Failure to do so will result in, ahem, unpleasantness. Extreme
225 * unpleasantness. "Him fall down, go boom."
227 * This /may/ change in the near future (ie. to apply caching in a
228 * transparent manner), so do keep a backup of files.c (and any other files
229 * you modify). You always keep backups anyway, don't you? Don't you?!
234 * if defined then some caching functions will be compiled for use by the
235 * various get_rnd_line(), etc. in files.c. This could be used in a
236 * variety of places that read data repeatedly, but it's up to you to
240 /* #define USE_FILECACHE */
244 * This causes lines beginning with '#' (and blank lines) to be discarded
245 * when caching files. This should help Zangband 2.2.5+ but could cause
246 * trouble for other variants. If defined, then smart file caching will be
250 /* #define SMART_FILECACHE */
254 * ABBR_FILECACHE causes data read into file-cache to be compressed (using a
255 * simple set of abbreviations) by default. This can be overridden using a
256 * command line option. If this symbol is not defined then no compression
257 * code will be compiled and the user option will be ignored/unavailable.
260 /* #define ABBR_FILECACHE */
264 * The following symbols control debugging information.
269 * If defined, some functions will be compiled to display some info. on the
270 * state of the front-end (accessible) from the '!' user menu.
272 * NB: For actual releases you should NOT define this symbol since it causes
273 * a non-negligable amount of code/data to be sucked in.
275 /* #define FE_DEBUG_INFO */
278 /* sCthAngband oddities */
280 #define SAVE_PLAYER_PARAM FALSE
281 #define PAUSE_LINE_PARAM
282 #define TERM_NAME(n) windows[n].name
283 #define TERM(i) windows[i].term
284 extern errr
check_modification_date(int fd
, cptr template_file
);
286 #define SAVE_PLAYER_PARAM
287 #define PAUSE_LINE_PARAM 23
288 #define TERM_NAME(n) angband_term_name[n]
289 #define TERM(i) angband_term[i]
293 /* NPP (for now) oddities */
295 extern void core(cptr str
);
298 /* V, post3.0.7, has conflicting types for these we have to #define around */
303 /* Constants, etc. ---------------------------------------------------------*/
305 /* Deal with any weird file-caching symbols */
306 #ifndef USE_FILECACHE
307 # undef ABBR_FILECACHE
308 # undef SMART_FILECACHE
311 /* Maximum terminals */
312 #define MAX_TERM_DATA 8
314 /* Menu entry numbers */
319 IBAR_MENU_FULLSCREEN
,
323 IBAR_MENU_SAVECHOICES
,
337 #define SND_VOL_SLIDER 0
338 #define SND_VOL_DOWN 1
349 #define SAVE_CANCEL 3
352 #define SIZE_HEIGHT 4
353 #define SIZE_CANCEL 7
356 /* Position and size of the colours strip in the gamma window */
362 /* Maximum and minimum allowed volume levels */
363 #define SOUND_VOL_MIN 16
364 #define SOUND_VOL_MAX 176
366 /*--------------------------------------------------------------------------*/
373 #include "Desklib:Event.h"
374 #include "Desklib:EventMsg.h"
375 #include "Desklib:Template.h"
376 #include "Desklib:Window.h"
377 #include "Desklib:Handler.h"
378 #include "Desklib:Screen.h"
379 #include "Desklib:Menu.h"
380 #include "Desklib:Msgs.h"
381 #include "Desklib:Icon.h"
382 #include "Desklib:Resource.h"
383 #include "Desklib:SWI.h"
384 #include "DeskLib:Str.h"
385 #include "Desklib:Time.h"
386 #include "Desklib:Sound.h"
387 #include "Desklib:KeyCodes.h"
388 #include "Desklib:Kbd.h"
389 #include "Desklib:GFX.h"
390 #include "Desklib:ColourTran.h"
391 #include "Desklib:Error.h"
392 #include "Desklib:Coord.h"
393 #include "Desklib:Slider.h"
394 #include "Desklib:Hourglass.h"
395 #include "Desklib:Save.h"
396 #include "Desklib:KernelSWIs.h"
397 #include "DeskLib:File.h"
398 #include "DeskLib:Filing.h"
409 /*--------------------------------------------------------------------------*/
412 | We use the hourglass around calls to Wimp_Poll in an attempt to stop
413 | users thinking that the game has 'hung'.
414 | Kamband/Zangband and the Borg in particular can have quite long delays at
419 * Note that empty-bracketed macros aren't ANSI/ISO C89 defined. GCC and
420 * Norcroft don't mind them though.
422 #define START_HOURGLASS \
423 do { if (use_glass && !glass_on) { glass_on=1; Hourglass_Start(50); }} while (0)
424 #define STOP_HOURGLASS \
425 do { if (glass_on) { glass_on=0; Hourglass_Off(); } } while (0)
428 /*--------------------------------------------------------------------------*/
430 /*--------------------------------------------------------------------------*/
443 unsigned int double_height
:1;
444 unsigned int extension
:1;
445 unsigned int padding
:29;
451 int r_minx
; /* min x of redraw in pixels from LHS, incl */
452 int r_miny
; /* min y of redraw in pixels from top, incl */
453 int r_maxx
; /* max x of redraw in pixels from LHS, excl */
454 int r_maxy
; /* max y of redraw in pixels from top, excl */
456 void *r_screen
; /* DSA: address of screen to write to (0=>read) */
457 int r_bpl
; /* DSA: bytes per raster line */
459 int r_bpp
; /* log base 2 of bits per pixel */
460 int r_charw
; /* width of a character in pixels */
461 int r_charh
; /* height of a character in pixels */
462 void *r_caddr
; /* DSA: ->character cache | VDU: ->font name */
463 int r_cbpl
; /* DSA: #bytes/character line | VDU: x OS offset */
464 int r_cbpc
; /* DSA: #bytes/character | VDU: y OS offset */
466 int r_linesp
; /* line spacing (pixels) */
468 void *r_data
; /* -> text to display */
469 int r_scrollx
; /* see Redraw dox */
470 int r_scrolly
; /* see Redraw dox */
472 void *r_palette
; /* -> palette lookup table */
473 int r_for
; /* foreground colour at start of line */
474 int r_bac
; /* background colour at start of line */
476 void *r_workarea
; /* -> word aligned workspace */
478 int r_magx
; /* log2 x OS coords per pixel */
479 int r_magy
; /* log2 y OS coords per pixel */
481 int r_xsize
; /* width of screen in pixels */
482 int r_ysize
; /* height of screen in pixels */
484 unsigned int r_mode
; /* current screen mode */
490 | We cache font data using an array of 'font handles' (since there is a
491 | known maximum no. of fonts required).
492 | This is what a font 'handle' looks like:
496 char *name
; /* font name */
497 int usage
; /* usage count */
498 int w
, h
; /* width, height */
499 int f
, l
; /* first and last character defined */
500 void *bpp_1
; /* source bitmap */
501 void *bpp_n
; /* bitmap for the current screen mode */
506 | A struct to hold all the data relevant to a term window
510 term t
; /* The Term itself */
511 window_handle w
; /* Window handle */
512 ZapFont
*font
; /* Font */
513 wimp_box changed_box
; /* Area out of date */
516 wimp_point pos
; /* Cursor position */
517 BOOL visible
; /* visibility flag */
520 char name
[12]; /* Name to give menus opened from the term */
521 int def_open
; /* Open by default? */
522 wimp_box def_pos
; /* default position */
523 wimp_point def_scroll
; /* default scroll offset */
524 int unopened
; /* Has this window not been opened yet? */
530 /*--------------------------------------------------------------------------*/
531 /* ZapRedraw SWI numbers */
532 /*--------------------------------------------------------------------------*/
534 #define SWI_ZapRedraw_ 0x48480
535 #define SWI_ZapRedraw_RedrawArea (SWI_ZapRedraw_ + 0x00)
536 #define SWI_ZapRedraw_GetPaletteEntry (SWI_ZapRedraw_ + 0x01)
537 #define SWI_ZapRedraw_RedrawRaster (SWI_ZapRedraw_ + 0x02)
538 #define SWI_ZapRedraw_ConvertBitmap (SWI_ZapRedraw_ + 0x03)
539 #define SWI_ZapRedraw_PrepareDataLine (SWI_ZapRedraw_ + 0x04)
540 #define SWI_ZapRedraw_AddCursor (SWI_ZapRedraw_ + 0x05)
541 #define SWI_ZapRedraw_FindCharacter (SWI_ZapRedraw_ + 0x06)
542 #define SWI_ZapRedraw_MoveBytes (SWI_ZapRedraw_ + 0x07)
543 #define SWI_ZapRedraw_CachedCharSize (SWI_ZapRedraw_ + 0x08)
544 #define SWI_ZapRedraw_ConvBitmapChar (SWI_ZapRedraw_ + 0x09)
545 #define SWI_ZapRedraw_CreatePalette (SWI_ZapRedraw_ + 0x0a)
546 #define SWI_ZapRedraw_InsertChar (SWI_ZapRedraw_ + 0x0b)
547 #define SWI_ZapRedraw_ReadSystemChars (SWI_ZapRedraw_ + 0x0c)
548 #define SWI_ZapRedraw_ReverseBitmaps (SWI_ZapRedraw_ + 0x0d)
549 #define SWI_ZapRedraw_ReadVduVars (SWI_ZapRedraw_ + 0x0e)
550 #define SWI_ZapRedraw_GetRectangle (SWI_ZapRedraw_ + 0x0f)
551 #define SWI_ZapRedraw_AddVduBitmaps (SWI_ZapRedraw_ + 0x10)
552 #define SWI_ZapRedraw_CacheFontChars (SWI_ZapRedraw_ + 0x11)
553 #define SWI_ZapRedraw_SpriteSize (SWI_ZapRedraw_ + 0x12)
554 #define SWI_ZapRedraw_RedrawWindow (SWI_ZapRedraw_ + 0x13)
558 | Other SWI numbers that aren't defined in DeskLib's SWI.h:
560 #define SWI_ColourTrans_ReturnColourNumber 0x40744
561 #define SWI_Wimp_ReportError 0x400df
562 #define SWI_PlayIt_Volume 0x4d146
566 /*--------------------------------------------------------------------------*
567 | File scope variables |
568 *--------------------------------------------------------------------------*/
569 static int ftype
= 0xffd; /* hack so saved games get the right type */
570 static int filehandle
[16]; /* we keep track of open files with this */
571 static int openfiles
= 0; /* how many files are currently open */
576 static char resource_path
[260] = ""; /* Path pointng to "!Angband.Lib." */
577 static char scrap_path
[260] = ""; /* Path to create scrap files on */
578 static char choices_file
[3][260] =
579 { "", "", "" }; /* Choices paths (read/write, mirror, read) */
580 static char alarm_file
[2][260] =
581 { "", "" }; /* Alarm choices paths (read/write, mirror, read) */
583 | So we can use something more meaningful later...
584 | NB: Mirror is only meaningful for Choices and we don't
585 | even reserve space for alarm_file[CHFILE_MIRROR].
587 #define CHFILE_WRITE 0
588 #define CHFILE_READ 1
589 #define CHFILE_MIRROR 2
594 static int initialised
= 0; /* Used to determine whether to try to save */
595 static int game_in_progress
= 0; /* if Quit (or core() is called), etc. */
597 static byte a_palette
[256][4]; /* a copy of the raw Angband palette */
598 static unsigned int palette
[256]; /* palette as gamma'd bbggrrxx words */
599 static unsigned int zpalette
[256]; /* And our version for ZapRedraw */
600 static int gamma
= 100; /* assume gamma of 1.0 if unspecified */
602 static int enable_sound
= 0; /* enable sound FX */
603 static int sound_volume
= 127; /* Full volume */
604 static int force_mono
= 0; /* force monochrome */
605 static int start_fullscreen
= 0; /* start up full screen (added in 1.18) */
606 static int hack_flush
= 0; /* Should TERM_XTRA_FLUSH wait for all keys to be released? */
607 static int flush_scrap
= 1; /* Should any scrapfiles (incl. filecache) be deleted at exit? */
608 static int max_file_cache_size
= 64 << 10;
609 static unsigned int vfiletype
;
610 static int alarm_type
= 0; /* is there an alarm set? */
611 static int alarm_h
= 0, alarm_m
= 0; /* alarm time (midnight) */
612 static char alarm_message
[80] = "Time for bed!"; /* the message to give */
613 static int alarm_disp
= 0; /* is the alarm being displayed? */
614 static int alarm_beep
= 0; /* should be beep? */
615 static const char *alarm_types
[] =
616 { "Off", "On (one-shot)", "On (repeating)", "On (one-shot)" };
617 static unsigned int alarm_lastcheck
= 0;
620 /* A little macro to save some typing later: */
621 #define COLOUR_CHANGED(x) \
622 ( (angband_color_table[x][1]!=a_palette[x][1]) || \
623 (angband_color_table[x][2]!=a_palette[x][2]) || \
624 (angband_color_table[x][3]!=a_palette[x][3]) )
626 static int got_caret
= 0; /* Do we own the caret? */
627 static int key_pressed
= 0; /* 'Key has been pressed' Flag */
628 static int use_glass
= 1; /* use the hourglass between WimpPolls? */
629 static int glass_on
= 1; /* is the hourglass on? */
630 static int user_menu_active
= FALSE
; /* set to TRUE when the user menu is active */
632 /* Font system variables */
633 static ZapFont fonts
[MAX_TERM_DATA
+ 1]; /* The +1 is for the system font */
635 /* The system font is always font 0 */
636 #define SYSTEM_FONT (&(fonts[0]))
638 /* Term system variables */
639 static term_data data
[MAX_TERM_DATA
]; /* One per term */
641 #ifndef FULLSCREEN_ONLY
642 static char *r_data
= NULL
; /* buffer for ZapRedraw data */
643 static int r_maxwid
, r_maxhgt
;
646 static icon_handle ibar_icon
; /* Iconbar icon handle */
647 static window_handle info_box
; /* handle of the info window */
648 static window_handle resize_win
; /* term resizing window */
649 static window_handle gamma_win
; /* gamma correction window */
650 static window_handle sound_win
; /* sound options window */
651 static window_handle save_box
; /* The savebox */
652 static menu_ptr ibar_menu
; /* Iconbar menu */
653 static menu_ptr term_menu
; /* Term window menu */
654 static menu_ptr wind_menu
; /* windows (sub) menu */
655 static menu_ptr font_menu
; /* Font (sub)menu */
657 static save_saveblock
*saveblk
= NULL
; /* For the save box */
659 static term_data
*menu_term
; /* term the last menu was opened for */
661 #endif /* FULLSCREEN_ONLY */
663 static ZapRedrawBlock zrb
; /* a redraw block */
666 #define CURSOR_COLOUR 255 /* Cursor's Angband colour */
667 #define CURSOR_RGB 0x00ffff00 /* if undefined, use bbggrrxx */
669 static int cursor_rgb
= -1; /* colour to use for cursor */
671 static int fullscreen_mode
= 0; /* screen mode in use */
672 static int old_screenmode
= 0; /* Mode we started out in */
673 static int *fullscreen_font
= 0; /* font data for fullscreen use */
674 static int *fullscreen_base
= 0; /* base address of screen */
675 static int fullscreen_height
; /* height of the fullscreen font */
676 static int fullscreen_topline
; /* raster offset of fullscreen */
678 #define KEYPRESS_QUIT 0x1cc /* F12 gets back to the desktop */
679 #define TERM_TOPLINE_HR 32 /* vertical pixel offset in mode 27 */
680 #define TERM_TOPLINE_LR 16 /* vertical pixel offset in mode 12 */
681 #define TIME_LINE 26 /* Line to display the clock on */
683 /* text to display at the bottom left of the fullscreen display */
684 static const char *fs_quit_key_text
= "Press f12 to return to the desktop";
685 static const char *alarm_cancel_text
= "(Press ^Escape to cancel the alarm)";
687 /* Debugging flags, etc. */
688 static int log_g_malloc
= 0; /* Log calls to ralloc, etc */
689 static int show_sound_alloc
= 0; /* Log sound mappings, etc */
691 /* Activate file caching? */
693 static int use_filecache
= TRUE
;
695 static int use_filecache
= FALSE
;
698 /* Cripple some things to save memory */
699 static int minimise_memory
= 0;
701 /* Forward declarations of some of the Full Screen Mode stuff */
702 static void enter_fullscreen_mode(void);
703 static void leave_fullscreen_mode(void);
704 static void set_keys(int claim
);
706 /* Forwards declarations of the sound stuff */
707 static void initialise_sound(void);
708 static void play_sound(int event
);
710 /* Forward declarations of Term hooks, etc. */
711 static void Term_init_acn(term
*t
);
712 static errr
Term_user_acn(int n
);
714 #ifndef FULLSCREEN_ONLY
715 static errr
Term_curs_acn(int x
, int y
);
716 static errr
Term_text_acn(int x
, int y
, int n
, byte a
, cptr s
);
717 static errr
Term_xtra_acn(int n
, int v
);
718 static errr
Term_wipe_acn(int x
, int y
, int n
);
719 static errr
Term_xtra_acn_check(void);
720 static errr
Term_xtra_acn_event(void);
721 static errr
Term_xtra_acn_react(void);
722 #endif /* FULLSCREEN_ONLY */
724 static errr
Term_curs_acnFS(int x
, int y
);
725 static errr
Term_text_acnFS(int x
, int y
, int n
, byte a
, cptr s
);
726 static errr
Term_wipe_acnFS(int x
, int y
, int n
);
727 static errr
Term_xtra_acn_clearFS(void);
728 static errr
Term_xtra_acn_eventFS(int);
729 static errr
Term_xtra_acn_reactFS(int force
);
730 static void bored(void);
731 static void redraw_areaFS(int x
, int y
, int w
, int h
);
732 static void draw_cursor(int x
, int y
);
735 /* Forward declarations of the memory stuff */
736 static void init_memory(int, int);
739 /* Forward declarations of the alarm stuff */
740 static void check_alarm(void);
741 #ifndef FULLSCREEN_ONLY
742 static void trigger_alarm_desktop(void);
743 #endif /* FULLSCREEN_ONLY */
744 static void ack_alarm(void);
745 static void write_alarm_choices(void);
746 static void read_alarm_choices(void);
749 /* This just shows some debugging info (if enabled with FE_DEBUG_INFO) */
750 static void show_debug_info(void);
754 /* File-caching functions (if enabled at compile time) */
756 FILE *cached_fopen(char *name
, char *mode
);
757 errr
cached_fclose(FILE *fch
);
758 errr
cached_fgets(FILE *fch
, char *buffer
, int max_len
);
763 * There are various different ways in which the g_malloc and g_free functions
764 * are prototyped, depending on the variant. This is an attempt to unify the
765 * codebase across thoe variants.
768 #define G_MALLOC_PROT static void *g_malloc(size_t size)
769 #define G_FREE_PROT static void *g_free(void *blk)
771 #define G_MALLOC_PROT static vptr g_malloc(huge size)
772 #define G_FREE_PROT static vptr g_free(vptr blk, huge size)
774 #define G_MALLOC_PROT static vptr g_malloc(huge size)
775 #define G_FREE_PROT static errr g_free(vptr blk, huge size)
779 | These functions act as malloc/free, but (if possible) using memory
780 | in the 'Game' Dynamic Area created by init_memory()
781 | We attach these functions to the ralloc_aux and rnfree_aux hooks
782 | that z-virt.c provides.
788 #define g_malloc(size) malloc(size);
790 #define g_free(block, size) free(block);
792 #define g_free(block) free(block);
797 | These functions act as malloc/free, but (if possible) using memory
798 | in the 'Fonts' Dynamic Area created by init_memory()
801 static void* f_malloc(size_t size
);
802 static void f_free(void *blk
);
804 #define f_malloc(size) malloc(size);
805 #define f_free(block) free(block);
811 | We use this to locate the choices file(s)...
813 static char *find_choices(int write
);
814 static char *find_choices_mirror(void);
815 static char *find_alarmfile(int write
);
820 | This function is supplied as a wrapper to the save_player function.
822 | Its purpose is to change the filename that the game will be saved with
823 | the leafname "!!PANIC!!" so that panic saves that break the savefile
824 | won't overwrite the original savefile.
826 | To get this to work, you'll need to ammend files.c and change the call
827 | to save_player in the panic save function(s) (search for "panic save")
828 | to a call to save_player_panic_acn. You can declare a prototype for
829 | the function if you like.
832 extern int save_player_panic_acn(void)
836 /* Find the final / in the savefile name */
837 for (l
= e
= savefile
; *e
; e
++)
843 /* Write over the current leaf with the special panic one */
844 strcpy(l
, "!!PANIC!!");
847 return save_player(SAVE_PLAYER_PARAM
);
851 /*--------------------------------------------------------------------------*/
852 /* Error reporting, etc. */
853 /*--------------------------------------------------------------------------*/
856 /* Tell the user something important */
857 static void plog_hook(cptr str
)
859 Msgs_Report(1, "err.plog", str
);
862 /* Tell the user something, then quit */
863 static void quit_hook(cptr str
)
865 /* str may be null */
866 if (str
) Msgs_Report(1, "err.quit", str
);
870 /* Tell the user something then crash ;) */
871 static void core_hook(cptr str
)
873 Msgs_Report(1, "err.core", str
);
875 if (game_in_progress
&& character_generated
)
876 save_player_panic_acn();
881 static void debug(const char *fmt
, ...)
887 vstrnfmt(buffer
, sizeof(buffer
), fmt
, ap
);
897 /*--------------------------------------------------------------------------*/
899 /*--------------------------------------------------------------------------*/
902 * We use myFile_WriteBytes and myFile_ReadBytes because we require a
903 * different return value to that given by the DeskLib "File_" equivalents.
905 static int myFile_WriteBytes(const int handle
, const void *buf
, const int n
)
908 if (SWI(4, 4, SWI_OS_GBPB
, 2, handle
, buf
, n
, /**/ NULL
, NULL
, NULL
, &ntf
))
913 static int myFile_ReadBytes(const int handle
, void *buf
, const int n
)
916 if (SWI(4, 4, SWI_OS_GBPB
, 4, handle
, buf
, n
, /**/ NULL
, NULL
, NULL
, &ntf
))
923 | Determine if one file is newer than another.
925 | The filenames should be specified in RISC OS style.
927 | Returns -1 if 'a' is newer than 'b'.
929 static int file_is_newer(const char *a
, const char *b
)
931 unsigned char a_time
[5];
932 unsigned char b_time
[5];
935 /* If 'a' doesn't exist then 'b' isn't out of date */
936 if (!File_Exists(a
)) return 0;
938 /* If 'b' doesn't exist then 'b' is out of date */
939 if (!File_Exists(b
)) return -1;
941 /* Get the datestamp of the 'a' file */
942 File_Date(a
, a_time
);
944 /* Get the datestamp of the 'b' file */
945 File_Date(b
, b_time
);
947 /* Compare timestamps, defaulting to 0 if they are of equal age */
948 for (n
= 4; n
>= 0; n
--)
950 if (b_time
[n
] < a_time
[n
])
954 if (b_time
[n
] > a_time
[n
]) return 0;
962 | As fprintf, but output to all files (if their handles are non zero).
965 static void f2printf(FILE *a
, FILE *b
, const char *fmt
, ...)
970 vstrnfmt(buffer
, sizeof(buffer
), fmt
, ap
);
973 if (a
) fprintf(a
, buffer
);
974 if (b
) fprintf(b
, buffer
);
982 /*--------------------------------------------------------------------------*/
983 /* Clean up (ie. close files, etc). */
984 /*--------------------------------------------------------------------------*/
986 static void final_acn(void)
990 for (i
= 0; i
< openfiles
; i
++) File_Close(filehandle
[i
]);
994 /* Restore the screen mode */
995 Wimp_SetMode(old_screenmode
);
997 /* Restore the various soft keys */
1001 if (flush_scrap
&& *scrap_path
)
1004 my_strcpy(tmp
, scrap_path
, sizeof(tmp
));
1005 tmp
[strlen(tmp
) - 1] = 0; /* Remove trailing dot */
1007 /* ie. "*Wipe <scrapdir> r~c~v~f" */
1008 SWI(4, 0, SWI_OS_FSControl
, 27, tmp
, 0, 1);
1011 #ifdef FULLSCREEN_ONLY
1012 Wimp_CommandWindow(-1);
1013 #endif /* FULLSCREEN_ONLY */
1019 /*--------------------------------------------------------------------------*
1020 | Various UNIX-like support funtions |
1021 *--------------------------------------------------------------------------*/
1024 | Hack: determine whether filenames should be truncated to 10 chars or not.
1026 | Needed since RO2 (and RO3 with Truncate configured off) will return
1027 | errors instead of automatically truncating long filenames.
1029 static int truncate_names(void)
1033 /* Okay, so we've got RO3 (or later), so check the CMOS RAM */
1034 OS_Byte(osbyte_READCMOSRAM
, 28, 0, &r1
, &r2
);
1036 /* Bit 0 of byte 28 is the Truncate flag */
1042 | The PathName translation is now done by two separate functions:
1043 | unixify_name() and riscosify_name().
1045 | This is done because only the UNIX=>RISCOS translation should
1046 | ever affect the length of the leafname (ie. by truncating it to
1047 | 10 chars if necessary).
1049 | Note that the two functions are identical but for the truncation
1050 | check so all that's really been done is that translate_name() now
1051 | takes an extra argument: 'trunc' that controls whether truncation
1052 | is applied, and riscosify and unixify just call translate_name().
1054 static char *translate_name(const char *path
, int trunc
)
1056 static char buf
[260];
1059 /* Copy 'path' into 'buf', swapping dots and slashes */
1060 p
= buf
; /* Output position */
1070 while (c
); /* Terminator /is/ copied */
1073 | When saving a game, the old game is renamed as
1074 | "SavedGame.old", the new one is saved as "SavedGame.new",
1075 | "SavedGame.old" is deleted, "SavedGame.new" is renamed
1076 | as "SavedGame". This will go wrong on a Filecore based filing
1077 | system if the saved game has a leafname > 8 chars.
1080 if ((p
= strstr(buf
, "/old")) == NULL
)
1082 p
= strstr(buf
, "/new");
1090 char *q
= strrchr(buf
, '.');
1094 memmove(q
+ 6, p
, 5);
1100 | Hack: Do we need to truncate the leafname?
1104 if (truncate_names())
1108 | Assume that only the leafname needs attention
1109 | (this should be true for any variant)
1111 for (a
= b
= buf
; *a
; a
++)
1115 | Now b points to the start of the leafname.
1116 | If the leafname is >10 chars, write over the 10th with a
1130 extern char *riscosify_name(const char *path
)
1132 return translate_name(path
, TRUE
);
1135 static char *unixify_name(const char *path
)
1137 return translate_name(path
, FALSE
);
1141 /*--------------------------------------------------------------------------*/
1145 * Open a file [as fopen()] but translate the requested filename first
1147 FILE *my_fopen(const char *f
, const char *m
)
1150 char *n
= riscosify_name(f
); /* translate for RO */
1152 /* Try to open the file */
1155 /* If it succeded and the file was opened for binary output
1156 | then set the type according to the 'ftype' hack.
1157 | NB: This will fail on some filing systems.
1160 if (fp
&& strstr(m
, "wb"))
1162 File_SetType(n
, ftype
);
1170 * Close a file, a la fclose()
1174 void my_fclose(FILE *fp
)
1176 #define RETURN return
1177 errr
my_fclose(FILE *fp
)
1180 /* Close the file, return 1 for an error, 0 otherwise */
1181 RETURN
fclose(fp
) ? 1 : 0;
1187 * Open/Create a file
1189 int fd_make(cptr file
, int mode
)
1194 /* Translate the filename into a RISCOS one */
1195 real_path
= riscosify_name(file
);
1197 /* Try to OPENOUT the file (no path, error if dir or not found) */
1198 handle
= File_Open(real_path
, (file_access
) 0x8f);
1200 /* Check for failure */
1201 if (!handle
) return -1;
1203 /* Try to set the filetype according to the ftype hack */
1204 File_SetType(real_path
, ftype
);
1206 /* We keep track of up to 16 open files at any given time */
1207 if (openfiles
< 16) filehandle
[openfiles
++] = handle
;
1209 return (int) handle
;
1213 /* Delete a file [as remove()] */
1214 errr
fd_kill(cptr file
)
1216 return remove(riscosify_name(file
)) ? 1 : 0;
1220 /* Rename a file [as rename()] */
1221 errr
fd_move(cptr old
, cptr
new)
1224 my_strcpy(new_
, riscosify_name(new), sizeof(new_
));
1225 return rename(riscosify_name(old
), new_
) ? 1 : 0;
1229 int fd_open(cptr path
, int flags
)
1231 file_handle handle
= 0;
1232 char *real_path
= riscosify_name(path
);
1234 switch (flags
& 0x0f)
1236 case O_RDONLY
: /* Read only */
1237 handle
= File_Open(real_path
, (file_access
) 0x4f);
1239 case O_WRONLY
: /* Write only */
1240 case O_RDWR
: /* Read/Write */
1241 handle
= File_Open(real_path
, (file_access
) 0xcf);
1244 /* Check for failure */
1245 if (!handle
) return (-1);
1247 /* Keep track of upto 16 open files... */
1249 filehandle
[openfiles
++] = handle
;
1251 return (int) handle
;
1255 /* Close a file opened with fd_make or fd_open */
1256 errr
fd_close(int handle
)
1263 } /* Illegal handle */
1265 /* Try to close the file */
1266 if (File_Close(handle
))
1271 /* Mark the file as closed in our array of file handles */
1273 /* Find the entry in the array (if it exists) */
1274 for (i
= 0; i
< 16; i
++)
1275 if (filehandle
[i
] == handle
)
1279 /* Shuffle the remaining entries down */
1280 for (; i
< openfiles
; i
++)
1281 filehandle
[i
] = filehandle
[i
+ 1];
1283 return 0; /* Sucess */
1288 /* Read some bytes from a file */
1290 errr
fd_read(int handle
, char *buf
, huge nbytes
)
1292 errr
fd_read(int handle
, char *buf
, huge nbytes
)
1294 errr
fd_read(int handle
, char *buf
, size_t nbytes
)
1299 /* Check the handle is legal */
1300 if (handle
<= 0) return -1;
1302 unread
= myFile_ReadBytes(handle
, buf
, (int) nbytes
);
1304 return unread
? 1 : 0;
1308 /* Write some bytes to a file */
1310 errr
fd_write(int handle
, const char *buf
, huge nbytes
)
1312 errr
fd_write(int handle
, cptr buf
, huge nbytes
)
1314 errr
fd_write(int handle
, const char *buf
, size_t nbytes
)
1319 /* Check the handle is legal */
1320 if (handle
<= 0) return -1;
1322 unwritten
= myFile_WriteBytes(handle
, buf
, (int)nbytes
);
1324 return unwritten
? 1 : 0;
1328 /* Seek in a file */
1330 errr
fd_seek(int handle
, huge offset
)
1332 errr
fd_seek(int handle
, long offset
)
1334 errr
fd_seek(int handle
, long offset
)
1339 /* Check the handle is legal */
1340 if (handle
<= 0) return -1;
1342 e
= File_Seek(handle
, (int)offset
);
1348 /* RISC OS provides no file locking facilities, so: */
1349 errr
fd_lock(int handle
, int what
)
1355 /* Get a temporary filename */
1356 errr
path_temp(char *buf
, int max
)
1360 | New in 1.25 - use the scrap path we decided on earlier, or
1361 | fall back on tmpnam() if that fails for some reason.
1370 * We try up to eighty scrapfiles based on the current time
1371 * until we find a filenane that doesn't yet exist.
1374 for (m
= 0; m
< 80; m
++)
1376 sprintf(tmp
, "%s0x%08x", scrap_path
, (int) t
+ m
);
1378 if (File_Size(tmp
) == -1) break;
1383 strncpy(buf
, unixify_name(tmp
), max
);
1388 strncpy(buf
, unixify_name(tmpnam(NULL
)), max
);
1393 int access(const char *path
, int mode
)
1398 e
= SWI(2, 1, SWI_OS_Find
, (1<<2) | (1<<3) | 0x40, riscosify_name(path
), &f
);
1400 if (e
|| f
== 0) return -1;
1402 SWI(2, 0, SWI_OS_Find
, 0, f
);
1410 * Create a new path by appending a file (or directory) to a path
1412 * This requires no special processing on simple machines, except
1413 * for verifying the size of the filename, but note the ability to
1414 * bypass the given "path" with certain special file-names.
1416 * Note that the "file" may actually be a "sub-path", including
1417 * a path and a file.
1419 * Note that this function yields a path which must be "parsed"
1420 * using the "parse" function above.
1422 #if PATHBUILDTYPE == 1
1423 void path_build(char *buf
, int max
, cptr path
, cptr file
)
1424 #elif PATHBUILDTYPE == 2
1425 errr
path_build(char *buf
, int max
, cptr path
, cptr file
)
1427 errr
path_build(char *buf
, size_t max
, cptr path
, cptr file
)
1433 /* Use the file itself */
1434 strnfmt(buf
, max
, "%s", file
);
1437 /* Absolute file, on "normal" systems */
1438 else if (prefix(file
, PATH_SEP
) && !streq(PATH_SEP
, ""))
1440 /* Use the file itself */
1441 strnfmt(buf
, max
, "%s", file
);
1447 /* Use the file itself */
1448 strnfmt(buf
, max
, "%s", file
);
1454 /* Build the new path */
1455 strnfmt(buf
, max
, "%s%s%s", path
, PATH_SEP
, file
);
1458 #if PATHBUILDTYPE > 1
1466 /*--------------------------------------------------------------------------*/
1472 /*--------------------------------------------------------------------------*/
1473 /* Font Functions */
1474 /*--------------------------------------------------------------------------*/
1477 | Cache the system font as fonts[0]
1478 | Returns 1 for sucess or 0 for failure.
1479 | NB: The n_bpp data is *not* cached, just the 1bpp data and font info.
1480 | Also, the usage is never affected.
1482 static int cache_system_font(void)
1484 ZapFont
*sys
= SYSTEM_FONT
;
1489 /* Cache the system font (as fonts[0]) */
1495 sys
->bpp_1
= f_malloc(8 * 256); /* 2K */
1501 /* Mung so that undefined characters show up as inverted ?s */
1503 SWI(2, 0, SWI_OS_Word
, 10, work_area
+ 3);
1504 for (i
= 4; i
< 12; i
++)
1505 work_area
[i
] ^= 255; /* invert colours */
1506 SWI(4, 0, SWI_ZapRedraw_ReverseBitmaps
, 0, work_area
+ 4, work_area
+ 4, 8);
1507 for (i
= 0; i
< 0x20; i
++)
1508 memcpy(((char *)sys
->bpp_1
) + i
* 8, work_area
+ 4, 8);
1510 /* Read the system font */
1511 zrb
.r_workarea
= work_area
;
1512 SWI(2, 0, SWI_ZapRedraw_ReadSystemChars
, sys
->bpp_1
, &zrb
);
1514 /* Set up some little bits of info */
1515 sys
->name
= (char *) "<System>";
1516 sys
->w
= sys
->h
= 8;
1526 | Prepare the font system
1528 static void initialise_fonts(void)
1530 /* Initialise the array */
1531 memset(fonts
, 0, sizeof(fonts
));
1533 /* Cache the system font */
1534 cache_system_font();
1535 fonts
[0].usage
= 0; /* No users */
1539 #ifndef FULLSCREEN_ONLY
1541 | Find a font (by name) in the array.
1542 | Returns 0 if the font isn't loaded, or a ZapFont* for it if it is.
1544 static ZapFont
*find_font_by_name(char *name
)
1547 for (i
= 0; i
<= MAX_TERM_DATA
; i
++)
1549 if (!strcmp(fonts
[i
].name
, name
))
1555 | Find a free slot in the fonts array
1557 static ZapFont
*find_free_font(void)
1560 for (i
= 1; i
<= MAX_TERM_DATA
; i
++)
1568 #ifndef HAS_MY_STRCPY
1570 * The my_strcpy() function copies up to 'bufsize'-1 characters from 'src'
1571 * to 'buf' and NUL-terminates the result. The 'buf' and 'src' strings may
1574 * my_strcpy() returns strlen(src). This makes checking for truncation
1575 * easy. Example: if (my_strcpy(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
1577 * This function should be equivalent to the strlcpy() function in BSD.
1579 size_t my_strcpy(char *buf
, const char *src
, size_t bufsize
)
1581 size_t len
= strlen(src
);
1585 if (bufsize
== 0) return ret
;
1588 if (len
>= bufsize
) len
= bufsize
- 1;
1590 /* Copy the string and terminate it */
1591 (void)memcpy(buf
, src
, len
);
1594 /* Return strlen(src) */
1597 #endif /* !HAS_MY_STRCPY */
1599 #ifndef HAS_MY_STRCAT
1601 * The my_strcat() tries to append a string to an existing NUL-terminated string.
1602 * It never writes more characters into the buffer than indicated by 'bufsize' and
1603 * NUL-terminates the buffer. The 'buf' and 'src' strings may not overlap.
1605 * my_strcat() returns strlen(buf) + strlen(src). This makes checking for
1606 * truncation easy. Example:
1607 * if (my_strcat(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
1609 * This function should be equivalent to the strlcat() function in BSD.
1611 static size_t my_strcat(char *buf
, const char *src
, size_t bufsize
)
1613 size_t dlen
= strlen(buf
);
1615 /* Is there room left in the buffer? */
1616 if (dlen
< bufsize
- 1)
1618 /* Append as much as possible */
1619 return (dlen
+ my_strcpy(buf
+ dlen
, src
, bufsize
- dlen
));
1623 /* Return without appending */
1624 return (dlen
+ strlen(src
));
1627 #endif /* !HAS_MY_STRCAT */
1631 | Load a font from disc and set up the header info, etc.
1632 | NB: doesn't cache the nbpp data, just the 1bpp data.
1634 | Returns NULL if failed.
1636 static ZapFont
*load_font(char *name
, ZapFont
*f
)
1643 int w
, h
, f
, l
, r1
, r2
;
1648 char *real_name
= name
; /* need to preserve this */
1651 | 1.10 - the first element of the name determines the path to load
1655 /* The font paths start <RISCOS_VARIANT>$ */
1656 t
= path
+ sprintf(path
, "%s$", RISCOS_VARIANT
);
1658 /* Copy the path specifier and move 'name' past it */
1659 for (; *name
!= '.'; *t
++ = *name
++) ;
1661 /* After this, the name now points to the font name proper */
1664 /* Append the end of the path name */
1665 strcpy(t
, "$FontPath");
1667 /* Get the path setting */
1668 font_path
= getenv(path
);
1669 if (!font_path
|| !*font_path
)
1670 my_strcpy(path
, "null:$.", sizeof(path
));
1673 my_strcpy(path
, font_path
, sizeof(path
));
1674 for (t
= path
; *t
> ' '; t
++)
1676 if (t
[-1] != '.' && t
[-1] != ':')
1682 my_strcat(path
, name
, sizeof(path
));
1686 handle
= File_Open(path
, (file_access
) 0x4f);
1692 /* Read the header */
1693 if (myFile_ReadBytes(handle
, &header
, sizeof(header
)))
1699 /* Check that it's a zapfont */
1700 if (strncmp(header
.id
, "ZapFont\r", 8))
1706 /* Calculate the size of the 1bpp data */
1707 extent
= File_ReadExtent(handle
) - sizeof(header
);
1709 /* Allocate the storage for the 1bpp data */
1710 f
->bpp_1
= f_malloc(extent
);
1717 /* Load the 1bpp data */
1718 if (myFile_ReadBytes(handle
, f
->bpp_1
, extent
))
1726 /* Close the file and set the header, etc. */
1728 f
->name
= f_malloc(strlen(real_name
) + 1);
1736 strcpy(f
->name
, real_name
);
1750 | Cache a font at a suitable number of bpp for the current mode
1751 | Returns 0 for failure, 1 for sucess.
1752 | If the call fails then the font's bpp_n entry will be NULL.
1754 static int cache_font_for_mode(ZapFont
*f
)
1757 char work_area
[128];
1769 b
.r_workarea
= work_area
;
1770 SWI(2, 0, SWI_ZapRedraw_ReadVduVars
, 0, &b
);
1772 b
.r_workarea
= work_area
; /* Paranoia */
1775 SWI(4, 4, SWI_ZapRedraw_CachedCharSize
, b
.r_bpp
, 0, f
->w
, f
->h
,
1776 NULL
, NULL
, &(b
.r_cbpl
), &(b
.r_cbpc
));
1778 size
= 256 * b
.r_cbpc
;
1784 f
->bpp_n
= f_malloc(size
);
1790 b
.r_workarea
= work_area
; /* Paranoia */
1791 b
.r_caddr
= f
->bpp_n
;
1792 SWI(5, 0, SWI_ZapRedraw_ConvertBitmap
, 0, &b
, 0, 255, f
->bpp_1
);
1800 | Stop using a font.
1801 | If the font's usage drops to zero then the font data is purged.
1803 static void lose_font(ZapFont
*f
)
1807 /*debug("Losing font %s (still cached)",f->name); */
1810 /*debug("Losing font %s (no longer in use)",f->name); */
1817 memset(f
, 0, sizeof(ZapFont
));
1824 static ZapFont
*find_font(char *name
)
1828 /* Check to see if it's already loaded */
1829 f
= find_font_by_name(name
);
1832 /*debug("Find font %s (already cached)",name); */
1834 if (f
== SYSTEM_FONT
)
1836 if (!cache_system_font())
1837 core("Failed to cache system font!");
1838 if (!cache_font_for_mode(SYSTEM_FONT
))
1839 core("Failed to cache system font!");
1844 /* Ok, now check to see if there's a free slot for it */
1845 f
= find_free_font();
1852 /*debug("Find font %s (loading)",name); */
1853 f
= load_font(name
, f
);
1856 if (!cache_font_for_mode(f
))
1867 | Cache the n_bpp data for all the active fonts (including system)
1869 static void cache_fonts(void)
1872 for (i
= 0; i
<= MAX_TERM_DATA
; i
++)
1874 if (!cache_font_for_mode(&(fonts
[i
])))
1875 core("Failed to (re)cache font tables");
1885 int load
, exec
, size
, attr
, type
;
1886 char name
[4]; /* Actual size is unknown */
1891 | NB: This function is recursive.
1893 static menu_ptr
make_zfont_menu(const char *dir
)
1897 unsigned int max_width
;
1901 filing_direntry
*item_info
;
1902 char buffer
[1024]; /* 1Kb buffer */
1904 /* Count the entries in the directory */
1905 entries
= offset
= 0;
1906 while (offset
!= -1)
1910 if (Filing_ReadDirNames(dir
, buffer
, &read
, &offset
, sizeof(buffer
), (char *) "*"))
1918 if (!entries
) return NULL
;
1920 /* Allocate a big enough area of storage for the number of entries */
1921 m
= f_malloc(sizeof(menu_block
) + entries
* sizeof(menu_item
));
1926 memset(m
, 0, sizeof(menu_block
) + entries
* sizeof(menu_item
));
1928 /* Set up the menu header */
1929 strncpy(m
->title
, Str_LeafName((char *) dir
), 12);
1936 mi
= (menu_item
*) (((int)m
) + sizeof(menu_block
));
1937 max_width
= strlen(m
->title
);
1941 /* Read the entries */
1943 while (offset
!= -1)
1947 if (Filing_ReadDirEntry(dir
, (filing_direntry
*) buffer
, &read
, &offset
, sizeof(buffer
), (char *) "*"))
1953 item_info
= (filing_direntry
*) buffer
;
1955 /* Create a menu item for each entry read (if it fits) */
1958 switch (item_info
->objtype
)
1962 if ((item_info
->loadaddr
& 0xffffff00) == 0xfffffd00)
1965 mi
[entry
].submenu
.value
= -1;
1966 mi
[entry
].iconflags
.data
.text
= 1;
1967 mi
[entry
].iconflags
.data
.filled
= 1;
1968 mi
[entry
].iconflags
.data
.foreground
= 7;
1969 mi
[entry
].iconflags
.data
.background
= 0;
1970 strncpy(mi
[entry
].icondata
.text
, item_info
->name
, 12);
1971 if (strlen(mi
[entry
].icondata
.text
) > max_width
)
1972 max_width
= strlen(mi
[entry
].icondata
.text
);
1978 case filing_DIRECTORY
:
1979 case filing_IMAGEFILE
:
1983 if (strchr(":.", dir
[strlen(dir
) - 1]))
1984 sprintf(new_path
, "%s%s", dir
, item_info
->name
);
1986 sprintf(new_path
, "%s.%s", dir
, item_info
->name
);
1987 sub
= make_zfont_menu(new_path
);
1990 /* Add the submenu */
1991 mi
[entry
].submenu
.menu
= sub
;
1992 mi
[entry
].iconflags
.data
.text
= 1;
1993 mi
[entry
].iconflags
.data
.filled
= 1;
1994 mi
[entry
].iconflags
.data
.foreground
= 7;
1995 mi
[entry
].iconflags
.data
.background
= 0;
1996 strncpy(mi
[entry
].icondata
.text
, item_info
->name
, 12);
1997 if (strlen(mi
[entry
].icondata
.text
) > max_width
)
1998 max_width
= strlen(mi
[entry
].icondata
.text
);
2006 temp
= ((char *) item_info
) + 20;
2008 item_info
= (filing_direntry
*) WORDALIGN((int) temp
);
2014 m
->width
= (max_width
+ 2) * 16;
2015 mi
[entry
- 1].menuflags
.data
.last
= 1;
2017 | We could possibly realloc() the storage to fit the
2018 | actual no. of entries read, but this is probably more
2019 | trouble than it's worth.
2024 /* No point in returning an empty menu. */
2032 #endif /* FULLSCREEN_ONLY */
2037 /*--------------------------------------------------------------------------*/
2040 | Initialise the palette stuff
2042 static void initialise_palette(void)
2044 memset(a_palette
, 0, sizeof(a_palette
));
2045 memset(palette
, 0, sizeof(palette
));
2046 memset(zpalette
, 0, sizeof(zpalette
));
2051 #ifndef FULLSCREEN_ONLY
2054 | Cache the ZapRedraw palette
2056 static void cache_palette(void)
2058 static ZapRedrawBlock b
;
2059 char workspace
[128];
2062 static int old_gamma
= -1;
2067 plog("Internal error: Attempt to apply zero gamma - recovering...");
2071 if (gamma
!= old_gamma
)
2073 memset(a_palette
, 0, sizeof(a_palette
));
2077 /* Go through the palette updating any changed values */
2078 for (i
= 0; i
< 256; i
++)
2080 if (COLOUR_CHANGED(i
))
2083 r
= (int)(255.0 * pow(angband_color_table
[i
][1] / 255.0, 1.0 / ((double) gamma
/ 100.0)));
2084 g
= (int)(255.0 * pow(angband_color_table
[i
][2] / 255.0, 1.0 / ((double) gamma
/ 100.0)));
2085 b
= (int)(255.0 * pow(angband_color_table
[i
][3] / 255.0, 1.0 / ((double) gamma
/ 100.0)));
2086 palette
[i
] = (b
<< 24) | (g
<< 16) | (r
<< 8);
2087 a_palette
[i
][1] = angband_color_table
[i
][1];
2088 a_palette
[i
][2] = angband_color_table
[i
][2];
2089 a_palette
[i
][3] = angband_color_table
[i
][3];
2093 cursor_rgb
= palette
[CURSOR_COLOUR
];
2095 /* Cache the ZapRedraw palette for it */
2096 b
.r_workarea
= workspace
;
2098 if (b
.r_mode
!= screen_mode
.screen_mode
)
2099 SWI(2, 0, SWI_ZapRedraw_ReadVduVars
, 0, &b
);
2101 SWI(5, 0, SWI_ZapRedraw_CreatePalette
, 2, &b
, palette
, zpalette
, 256);
2107 /*--------------------------------------------------------------------------*/
2110 | Functions for dealing with the SaveBox
2114 #ifndef HAS_MY_STRNICMP
2116 | Hack: can't use Str.h without defining HAS_STRICMP. Rather than
2117 | require that the header files are altered we simply provide our
2118 | own strnicmp() function.
2120 static int my_strnicmp(const char *a
, const char *b
, int n
)
2126 for (i
= 0; i
<= n
; i
++)
2128 if (tolower((unsigned char)a
[i
]) != tolower((unsigned char)b
[i
]))
2129 return tolower((unsigned char)a
[i
]) - tolower((unsigned char)b
[i
]);
2137 #endif /* HAS_MY_STRNICMP */
2141 | This is the handler called when a 'save' occurrs.
2142 | All it does is to update the game's own savefile setting and
2143 | then (if possible) save the character.
2145 static BOOL
SaveHnd_FileSave(char *filename
, void *ref
)
2147 char old_savefile
[1024];
2149 /* Hack: refuse to save if the character is dead */
2152 Msgs_Report(0, "err.cheat");
2156 /* Hack: disallow saves to <Wimp$Scrap>* */
2157 if (!my_strnicmp("<wimp$scrap>", filename
, 12))
2159 Msgs_Report(0, "err.scrap");
2163 /* Preserve the old path, in case something goes wrong... */
2164 my_strcpy(old_savefile
, savefile
, sizeof(old_savefile
));
2166 /* Set the new path */
2167 my_strcpy(savefile
, unixify_name(filename
), sizeof(savefile
));
2169 /* Try a save (if sensible) */
2170 if (game_in_progress
&& character_generated
)
2174 if (!save_player(SAVE_PLAYER_PARAM
))
2176 Msgs_Report(0, "err.save", filename
);
2177 my_strcpy(savefile
, old_savefile
, sizeof(savefile
));
2178 return FALSE
; /* => failure */
2183 Msgs_Report(0, "err.nosave");
2184 my_strcpy(savefile
, old_savefile
, sizeof(savefile
));
2185 return TRUE
; /* Failed really, but not unexpectedly */
2189 /* Set the pathname icon */
2190 Icon_printf(save_box
, SAVE_PATH
, "%s", riscosify_name(savefile
));
2192 return TRUE
; /* => Success */
2196 | Create the window and claim various handlers for it
2198 static void init_save_window(void)
2200 /* Create the window */
2201 save_box
= Window_Create("save", template_TITLEMIN
);
2203 /* Set the file icon */
2204 Icon_printf(save_box
, SAVE_ICON
, "file_%03x", vfiletype
);
2206 saveblk
= Save_InitSaveWindowHandler(save_box
, /* Window handle */
2207 TRUE
, /* it's part of a menu */
2208 FALSE
, /* not a window */
2209 FALSE
, /* Don't auto release the handlers */
2210 SAVE_ICON
, /* The file icon */
2211 SAVE_OK
, /* The OK icon */
2212 SAVE_CANCEL
, /* The cancel icon */
2213 SAVE_PATH
, /* The pathname icon */
2214 SaveHnd_FileSave
, /* Handler to "save the file" */
2215 NULL
, /* No RAM transfer support */
2216 NULL
, /* No 'result handler' */
2217 100 << 10, /* Est. size (irelevant anyway) */
2218 vfiletype
, /* filetype (irelevant) */
2225 | Handles MenuWarning messages
2227 static BOOL
Hnd_MenuWarning(event_pollblock
* pb
, void *ref
)
2232 if (menu_currentopen
== ibar_menu
)
2236 else if (menu_currentopen
== term_menu
)
2238 switch (pb
->data
.message
.data
.menuwarn
.selection
[0])
2240 case TERM_MENU_SAVE
: win
= save_box
; break;
2241 case TERM_MENU_SIZE
: win
= resize_win
; break;
2242 default: return FALSE
;
2250 if (win
== save_box
)
2252 /* Set the pathname */
2253 Icon_printf(save_box
, SAVE_PATH
, "%s", riscosify_name(savefile
));
2258 Icon_SetInteger(resize_win
, SIZE_WIDTH
, menu_term
->t
.wid
);
2259 Icon_SetInteger(resize_win
, SIZE_HEIGHT
, menu_term
->t
.hgt
);
2262 /* Open the submenu */
2263 e
= Wimp_CreateSubMenu((menu_block
*) win
,
2264 pb
->data
.message
.data
.menuwarn
.openpos
.x
,
2265 pb
->data
.message
.data
.menuwarn
.openpos
.y
);
2267 if (e
) Msgs_ReportFatal(0, "err.swi", __LINE__
, e
->errmess
);
2273 /*--------------------------------------------------------------------------*/
2277 * Initialise the r_data array, reallocating memory for it if the size of our
2278 * "theoretical largest term" has changed since the last call.
2280 * We just set up the line offset pointers and make sure that the
2281 * lines themselves are 'safe' by writing end-of-line codes to them.
2283 static void initialise_r_data(void)
2285 int maxwid
= 0, maxhgt
= 0;
2293 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
2295 if (data
[i
].t
.wid
> maxwid
) maxwid
= data
[i
].t
.wid
;
2296 if (data
[i
].t
.hgt
> maxhgt
) maxhgt
= data
[i
].t
.hgt
;
2299 if (r_maxwid
!= maxwid
|| r_maxhgt
!= maxhgt
)
2302 * We allocate enough memory for a theoretical largest zapredrawblock.
2303 * This consists of a list of line starts + terminator, then a big
2304 * block containing enough space for max_hgt lines of max_wid each
2305 * (allowing for possible control codes) and an end-of-line-terminator
2308 new_r_data
= realloc(r_data
,
2309 (maxhgt
+ 1) * 4 + maxhgt
* (maxwid
* 5 + 4));
2311 if (new_r_data
== NULL
)
2313 Msgs_Report(0, "err.resize");
2317 r_data
= new_r_data
;
2318 zrb
.r_data
= r_data
;
2324 lo
= (int *) r_data
;
2327 /* Make a dummy block where all lines point to the same empty line */
2328 ld
= r_data
+ (maxhgt
+ 1) * 4;
2329 *ld
++ = 0; /* 0,2 == */
2330 *ld
= 2; /* end of line */
2332 for (i
= 0; i
< maxhgt
; i
++)
2334 /* Offset of line */
2335 lo
[i
] = (maxhgt
+ 1) * 4;
2337 lo
[i
] = 0; /* Terminate line index */
2343 | Create the r_data array for a term
2344 | This is typically quite fast (1ms or so on a RPC700)
2345 | so we don't bother caching r_data for each term or using the
2348 static void make_r_data(term_data
*t
)
2350 char **c
= t
->t
.old
->c
; /* char array */
2351 byte
**a
= t
->t
.old
->a
; /* attr array */
2355 /* First byte of r_data after line index */
2356 o
= r_data
+ (t
->t
.hgt
+ 1) * 4;
2360 for (j
= 0; j
< t
->t
.hgt
; j
++)
2362 /* Set up the line offset entry */
2363 ((int *)r_data
)[j
] = o
- r_data
;
2365 for (i
= 0; i
< t
->t
.wid
; i
++)
2366 *o
++ = a
[j
][i
] != TERM_DARK
? c
[j
][i
] : ' ';
2367 /* 0,2 => end of line */
2374 for (j
= 0; j
< t
->t
.hgt
; j
++)
2376 /* Set up the line offset entry */
2377 ((int *)r_data
)[j
] = o
- r_data
;
2379 /* Each line starts in white */
2382 for (i
= 0; i
< t
->t
.wid
; i
++)
2386 /* 0,6 => change FG */
2389 cf
= *o
++ = a
[j
][i
];
2393 /* 0,2 => end of line */
2399 /* Terminate line index */
2400 ((int *) r_data
)[t
->t
.hgt
] = 0;
2405 | Set up 'zrb' for the current screen mode.
2407 static void set_up_zrb_for_mode(void)
2409 static char work_area
[4096];
2410 zrb
.r_workarea
= work_area
;
2411 zrb
.r_palette
= zpalette
;
2413 zrb
.r_for
= TERM_WHITE
;
2415 zrb
.r_data
= r_data
;
2416 SWI(2, 0, SWI_ZapRedraw_ReadVduVars
, 0, &zrb
);
2422 | Set up the ZapRedrawBlock ready to redraw term 't'
2423 | (caches the r_data as part of the process)
2425 static void set_up_zrb(term_data
*t
)
2429 zrb
.r_flags
.value
= 0;
2431 /* Set font info up */
2434 SWI(4, 4, SWI_ZapRedraw_CachedCharSize
, zrb
.r_bpp
, 0, fw
, fh
,
2435 NULL
, NULL
, &(zrb
.r_cbpl
), &(zrb
.r_cbpc
));
2436 zrb
.r_caddr
= (void *)(((int)t
->font
->bpp_n
) - (t
->font
->f
* zrb
.r_cbpc
));
2438 zrb
.r_charw
= fw
; /* Character size in pixels */
2441 if (t
->font
== SYSTEM_FONT
)
2442 zrb
.r_flags
.bits
.double_height
= screen_eig
.y
== 1;
2444 zrb
.r_flags
.bits
.double_height
= 0;
2446 make_r_data(t
); /* Cache the r_data */
2453 * Redraws the contents of the given term, as initialised by a
2454 * Wimp_RedrawWindow or Wimp_UpdateWindow call.
2456 static void RO_redraw_window(window_redrawblock
* rb
, BOOL
*more
, term_data
*t
)
2458 int cx
= 0, cy
= 0, cw
= 0, ch
= 0;
2460 /* set GCOL for cursor colour */
2461 if (t
->cursor
.visible
)
2463 cw
= zrb
.r_charw
<< screen_eig
.x
;
2464 ch
= -(zrb
.r_charh
<< screen_eig
.y
);
2465 if (zrb
.r_flags
.bits
.double_height
)
2469 cx
= t
->cursor
.pos
.x
* cw
;
2470 cy
= t
->cursor
.pos
.y
* ch
;
2471 cx
+= (rb
->rect
.min
.x
- rb
->scroll
.x
);
2472 cy
+= (rb
->rect
.max
.y
- rb
->scroll
.y
);
2473 cw
-= (1 << screen_eig
.x
);
2474 ch
+= (1 << screen_eig
.y
);
2475 cy
-= (1 << screen_eig
.y
);
2480 SWI(2, 0, SWI_ZapRedraw_GetRectangle
, rb
, &zrb
);
2481 SWI(2, 0, SWI_ZapRedraw_RedrawArea
, NULL
, &zrb
);
2482 if (t
->cursor
.visible
)
2484 ColourTrans_SetGCOL(cursor_rgb
, 0, 0);
2491 Wimp_GetRectangle(rb
, more
);
2499 * Perform the redraw for the requested term window.
2501 static BOOL
Hnd_Redraw(event_pollblock
* pb
, void *ref
)
2503 term_data
*t
= (term_data
*)ref
;
2504 window_redrawblock rb
;
2508 Wimp_RedrawWindow(&rb
, &more
);
2512 RO_redraw_window(&rb
, &more
, t
);
2521 * Redraw the out-of-date parts of the given term window
2523 static void refresh_window(term_data
*t
)
2525 window_redrawblock rb
;
2529 if ((t
->changed_box
.min
.x
>= t
->changed_box
.max
.x
) ||
2530 (t
->changed_box
.min
.y
>= t
->changed_box
.max
.y
))
2535 fw
= zrb
.r_charw
<< screen_eig
.x
;
2536 fh
= -(zrb
.r_charh
<< screen_eig
.y
);
2537 if (zrb
.r_flags
.bits
.double_height
)
2543 rb
.rect
.min
.x
= fw
* t
->changed_box
.min
.x
;
2544 rb
.rect
.max
.x
= fw
* t
->changed_box
.max
.x
;
2546 rb
.rect
.max
.y
= fh
* t
->changed_box
.min
.y
;
2547 rb
.rect
.min
.y
= fh
* t
->changed_box
.max
.y
;
2549 Wimp_UpdateWindow(&rb
, &more
);
2550 RO_redraw_window(&rb
, &more
, t
);
2552 t
->changed_box
.min
.x
= t
->changed_box
.min
.y
= 255;
2553 t
->changed_box
.max
.x
= t
->changed_box
.max
.y
= 0;
2558 * Redraws the out-of-date parts of the all the open term windows.
2560 static void refresh_windows(void)
2565 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
2567 info
.window
= data
[i
].w
;
2568 Wimp_GetWindowInfo(&info
);
2569 if (info
.block
.flags
.data
.open
) refresh_window(&(data
[i
]));
2575 | Set the size of a window.
2576 | If the window grows but has no scroll bars then it is re-sized to
2577 | the new extent. If it shrinks then it is resized regardless.
2579 | If the window isn't open then it is opened behind the backwindow,
2580 | resized and then closed again... I /did/ have a reason for doing this
2581 | rather than simply recreating the window at the new size, but for the
2582 | life of me I can't remember what it was...
2584 | <ajps> I think this is simply so that the Wimp remembers the position
2585 | of the window for when we next call show_windows().
2587 static void set_window_size(window_handle w
, int width
, int height
)
2592 Wimp_GetWindowState(w
, &ws
);
2593 Window_SetExtent(w
, 0, -height
, width
, 0);
2595 reclose
= !ws
.flags
.data
.open
;
2596 if (!(ws
.flags
.value
& (0xf << 27)))
2600 ws
.openblock
.behind
= -3;
2601 Wimp_OpenWindow(&(ws
.openblock
));
2604 /* Keep the top right-hand corner of the window fixed. */
2605 ws
.openblock
.screenrect
.max
.x
= ws
.openblock
.screenrect
.min
.x
+ width
;
2606 ws
.openblock
.screenrect
.min
.y
= ws
.openblock
.screenrect
.max
.y
- height
;
2608 Wimp_OpenWindow(&(ws
.openblock
));
2612 Wimp_CloseWindow(w
);
2632 | Change the size of a window to suit the font displayed in it
2634 static void force_term_resize(term_data
*t
)
2639 fw
= zrb
.r_charw
<< screen_eig
.x
;
2640 fh
= zrb
.r_charh
<< screen_eig
.y
;
2641 if (zrb
.r_flags
.bits
.double_height
)
2646 /* Calculate new size */
2650 set_window_size(t
->w
, fw
, fh
);
2655 * Change the actual size of the terminal (so as to support variable-sized
2656 * "bigscreen" windows.
2658 static void term_change_size(term_data
*t
, int wid
, int hgt
)
2662 /* Ignore attempts to resize too small */
2663 if (t
== &data
[0] && (wid
< 80 || hgt
< 24)) return;
2665 /* Hack -- activate the Term */
2666 Term_activate(&(t
->t
));
2668 /* Only do all the complicated stuff if the resize attempt succeeded */
2670 Term_resize(wid
, hgt
);
2672 if (Term_resize(wid
, hgt
) == NULL
)
2675 initialise_r_data();
2676 force_term_resize(t
);
2679 /* Hack -- restore the old Term */
2680 Term_activate(old_t
);
2690 static BOOL
Hnd_Caret(event_pollblock
* pb
, void *ref
)
2692 if (ref
) got_caret
= 1;
2702 | Attach a (named) font to the specified term.
2703 | If 'font' is NULL then the system font is attached.
2704 | The bpp_n data is calculated if necessary
2706 | 1 => the font was attached OK
2707 | 0 => the system font was substituted
2709 static int attach_font_to_term(term_data
*t
, char *font
)
2711 if (t
->font
!= SYSTEM_FONT
) lose_font(t
->font
);
2713 if (font
) t
->font
= find_font(font
);
2717 t
->font
= SYSTEM_FONT
;
2718 if (font
) Msgs_Report(1, "err.font_l", font
);
2722 if (!t
->font
->bpp_n
)
2725 t
->font
= SYSTEM_FONT
;
2726 if (font
) Msgs_Report(1, "err.font_c", font
);
2730 force_term_resize(t
);
2732 return !(t
->font
== SYSTEM_FONT
);
2738 /*--------------------------------------------------------------------------*/
2743 | Create a menu of all the (probable!) fonts in the specified location
2744 | NB: Any file of type 'data' is considered a font.
2746 | Subdirectories are recursively searched.
2748 | 1.10 - Uses <variant>$FontPaths to get a (space separated) list of paths
2749 | to search. For each path name, the menu text will be the name and the
2750 | path searched will be <variant>$<name>$FontPath
2752 | Eg. (for angband):
2753 | Angband$FontPaths Zap Angband
2754 | Angband$Zap$FontPath ZapFonts:
2755 | Angband$Angband$FontPath Angband:xtra.fonts.
2757 static void make_font_menu(void)
2761 char menu_buffer
[260];
2764 unsigned int max_width
;
2765 const char *path
[64]; /* pointers to path names */
2770 /* Get the path (ie. dir) to look under */
2771 t
= getenv(RISCOS_VARIANT
"$FontPaths");
2773 /* Hack: cope if the path isn't set */
2779 my_strcpy(buffer
, t
, sizeof(buffer
));
2782 | Count how many paths there are, build an array of pointers to them
2783 | and terminate them in the buffer
2785 paths
= 1; /* including the system font fake path '<System>' */
2786 for (t
= buffer
; *t
; t
++)
2794 if (t
== buffer
|| !t
[-1])
2805 path
[0] = SYSTEM_FONT
->name
;
2807 font_menu
= f_malloc(sizeof(menu_block
) + paths
* sizeof(menu_item
));
2810 core("Out of memory (building font menu)");
2812 memset(font_menu
, 0, sizeof(menu_block
) + paths
* sizeof(menu_item
));
2814 strncpy(font_menu
->title
, "Fonts", 12);
2815 font_menu
->titlefore
= 7;
2816 font_menu
->titleback
= 2;
2817 font_menu
->workfore
= 7;
2818 font_menu
->workback
= 0;
2819 font_menu
->height
= 44;
2821 max_width
= strlen(font_menu
->title
);
2823 mi
= (menu_item
*) (font_menu
+ 1);
2825 for (i
= 0; i
< paths
; i
++)
2827 mi
[i
].submenu
.value
= -1;
2828 mi
[i
].iconflags
.data
.text
= 1;
2829 mi
[i
].iconflags
.data
.filled
= 1;
2830 mi
[i
].iconflags
.data
.foreground
= 7;
2831 mi
[i
].iconflags
.data
.background
= 0;
2832 strncpy(mi
[i
].icondata
.text
, path
[i
], 12);
2833 if (strlen(mi
[i
].icondata
.text
) > max_width
)
2834 max_width
= strlen(mi
[i
].icondata
.text
);
2836 font_menu
->width
= (max_width
+ 2) * 16;
2837 mi
[i
- 1].menuflags
.data
.last
= 1;
2840 | Hack: add a dotted line after the system font entry if appropriate
2842 if (paths
> 1) mi
[0].menuflags
.data
.dotted
= 1;
2845 | Iterate over the paths, building the appropriate submenus
2847 for (i
= 1; i
< paths
; i
++)
2849 menu_ptr sub_menu
= NULL
;
2851 sprintf(menu_buffer
, "%s$%s$FontPath", RISCOS_VARIANT
, path
[i
]);
2852 t
= getenv(menu_buffer
);
2853 /* Hack: cope if the path isn't defined */
2859 /* Fudge so that the fontpath can be a path, not just a dir. */
2860 my_strcpy(menu_buffer
, t
, sizeof(menu_buffer
));
2861 for (t
= menu_buffer
; *t
> ' '; t
++)
2869 /* Build the menu. Don't bother if the path variable was empty */
2871 sub_menu
= make_zfont_menu(menu_buffer
);
2875 mi
[i
].iconflags
.data
.shaded
= 1;
2879 mi
[i
].submenu
.menu
= sub_menu
;
2880 /* Override the title of the 'root' sub-menu */
2881 strncpy(sub_menu
->title
, path
[i
], 12);
2882 /* Add the submenu to the main menu */
2889 /* ----------------------------------------------- musus, xxxx-xx-xx ---
2890 * Create and set up the infobox.
2891 * --------------------------------------------------------------------- */
2892 static void create_info_box(void)
2894 info_box
= Window_Create("info", template_TITLEMIN
);
2895 Icon_printf(info_box
, 0, "%s %s", VARIANT
, VERSION
);
2896 Icon_SetText(info_box
, 2, AUTHORS
);
2897 Icon_SetText(info_box
, 3, PORTERS
);
2898 Icon_SetText(info_box
, 7, PORTVERSION
);
2904 static BOOL
Hnd_ResizeSet(event_pollblock
*pb
, void *ref
)
2906 int newwid
= Icon_GetInteger(resize_win
, SIZE_WIDTH
);
2907 int newhgt
= Icon_GetInteger(resize_win
, SIZE_HEIGHT
);
2909 if (pb
->type
!= event_CLICK
|| pb
->data
.mouse
.button
.data
.adjust
== 0)
2911 Menu_Show((menu_ptr
) -1, -1, -1);
2914 /* Do simple validation of the values */
2915 if (menu_term
== &data
[0])
2917 if (newwid
< 80 || newhgt
< 24)
2919 Msgs_Report(0, "err.minsize1");
2923 else if (newwid
< 1 || newhgt
< 1)
2925 Msgs_Report(0, "err.minsize2");
2929 term_change_size(menu_term
, newwid
, newhgt
);
2935 static BOOL
Hnd_ResizeCancel(event_pollblock
*pb
, void *ref
)
2938 Menu_Show((menu_ptr
) -1, -1, -1);
2944 static BOOL
Hnd_ResizeKeypress(event_pollblock
*pb
, void *ref
)
2946 if(pb
->data
.key
.code
== keycode_RETURN
)
2947 return Hnd_ResizeSet(pb
, ref
);
2954 * Create and set up the term-resize window.
2956 static void create_resize_win(void)
2958 resize_win
= Window_Create("resize", template_TITLEMIN
);
2960 Event_Claim(event_CLICK
, resize_win
, SIZE_SET
, Hnd_ResizeSet
, NULL
);
2961 Event_Claim(event_CLICK
, resize_win
, SIZE_CANCEL
, Hnd_ResizeCancel
, NULL
);
2962 Event_Claim(event_KEY
, resize_win
, event_ANY
, Hnd_ResizeKeypress
, NULL
);
2970 | Create the various menus
2972 static void init_menus(void)
2980 create_resize_win();
2982 Msgs_Lookup("menu.ibar:Info|>Save As|Full screen,Gamma correction,Sound,"
2983 "Windows|Save choices|Quit (& save)", buffer1
, 256);
2984 ibar_menu
= Menu_New(VARIANT
, buffer1
);
2985 if (!ibar_menu
) core("Can't create Iconbar menu!");
2987 Msgs_Lookup("menu.term:Info|>Save As|>Size,Font,Windows", buffer1
, 256);
2988 term_menu
= Menu_New(VARIANT
, buffer1
);
2989 if (!term_menu
) core("Can't create Term menu!");
2991 #ifndef OLD_TERM_MENU
2993 o
+= sprintf(buffer1
, "%s|", VARIANT
);
2994 o
+= sprintf(o
, "%s,%s,%s|", TERM_NAME(1), TERM_NAME(2),
2996 sprintf(o
, "%s,%s,%s,%s", TERM_NAME(4), TERM_NAME(5),
2997 TERM_NAME(6), TERM_NAME(7));
2999 Msgs_printf(buffer1
, "menu.windows:%s|Term-1 (Mirror),Term-2 (Recall),"
3000 "Term-3 (Choice)|Term-4,Term-5,Term-6,Term-7", VARIANT
);
3002 Msgs_Lookup("menu.winT:Windows", buffer2
, 32);
3003 wind_menu
= Menu_New(buffer2
, buffer1
);
3006 core("Can't create Windows menu!");
3009 /* Now attach the various submenus to where they belong */
3010 Menu_AddSubWindow(ibar_menu
, IBAR_MENU_INFO
, info_box
);
3011 Menu_AddSubWindow(ibar_menu
, IBAR_MENU_GAMMA
, gamma_win
);
3012 Menu_AddSubWindow(ibar_menu
, IBAR_MENU_SOUND
, sound_win
);
3013 Menu_AddSubMenu(ibar_menu
, IBAR_MENU_WINDOWS
, wind_menu
);
3015 Menu_AddSubMenu(term_menu
, TERM_MENU_INFO
, (menu_ptr
) info_box
);
3016 Menu_AddSubMenu(term_menu
, TERM_MENU_WINDOWS
, wind_menu
);
3018 /* Add the handler for menu warnings */
3019 EventMsg_Claim(message_MENUWARN
, event_ANY
, Hnd_MenuWarning
, NULL
);
3021 /* Set up these menu items to issue menuwarn messages */
3022 /* Menu_Warn(ibar_menu, IBAR_MENU_SAVE, TRUE, NULL, NULL);
3023 Menu_Warn(term_menu, TERM_MENU_SAVE, TRUE, NULL, NULL);
3024 Menu_Warn(term_menu, TERM_MENU_SIZE, TRUE, NULL, NULL);*/
3027 /* add the submenu */
3028 Menu_AddSubMenu(term_menu
, TERM_MENU_FONT
, font_menu
);
3030 /* If the font menu is buggered, shade its entry */
3031 /* unticked, shaded */
3032 Menu_SetFlags(term_menu
, TERM_MENU_FONT
, FALSE
, TRUE
);
3038 static void grab_caret(void)
3041 cb
.window
= data
[0].w
;
3043 cb
.height
= 1 << 25; /* Invisible */
3044 Wimp_SetCaretPosition(&cb
);
3051 | (Recursively) clear all ticks from the specified menu
3053 static void clear_all_menu_ticks(menu_ptr mp
)
3055 menu_item
*mi
= (menu_item
*) (mp
+ 1);
3059 if (mi
->menuflags
.data
.ticked
) mi
->menuflags
.data
.ticked
= 0;
3061 if (mi
->submenu
.value
!= -1) clear_all_menu_ticks(mi
->submenu
.menu
);
3065 while (mi
[-1].menuflags
.data
.last
!= 1);
3074 | Set the font menu's ticks to match the specifed font name.
3076 | fm is the (sub) menu to scan down (recursing into it's submenus (if any))
3077 | fn is the font name to match
3078 | prefix is the menu text to be prepended to the menu entries due to
3079 | previous menus (eg. "08x16" will cause fn="08x16.fred" to match menu
3086 static void set_font_menu_ticks(menu_ptr fm
, char *fn
, const char *prefix
)
3089 char *b_leaf
; /* -> menu 'leaf' text in buffer */
3090 int pl
; /* prefix string length */
3091 menu_item
*mi
= (menu_item
*) (fm
+ 1);
3093 my_strcpy(buffer
, prefix
, sizeof(buffer
));
3095 pl
= strlen(buffer
);
3096 b_leaf
= buffer
+ pl
;
3100 /* Check for (substring) match */
3101 strncpy(b_leaf
, mi
->icondata
.text
, 12);
3103 /* Is it a sub-menu? */
3104 if (mi
->submenu
.value
== -1)
3106 /* No - must be an exact match */
3107 mi
->menuflags
.data
.ticked
= !strcmp(buffer
, fn
);
3111 /* Yes - must be a partial match (with a dot on :) */
3112 my_strcat(b_leaf
, ".", sizeof(buffer
) - pl
);
3113 mi
->menuflags
.data
.ticked
=
3114 !strncmp(buffer
, fn
, pl
+ strlen(b_leaf
));
3115 if (mi
->menuflags
.data
.ticked
)
3116 set_font_menu_ticks(mi
->submenu
.menu
, fn
, buffer
);
3118 clear_all_menu_ticks(mi
->submenu
.menu
);
3124 while (mi
[-1].menuflags
.data
.last
!= 1); /* Until finished */
3138 | Set ticks, etc. in the term_menu to reflect the current state of the
3141 static void set_up_term_menu(term_data
*t
)
3148 /* First of all, set up menu title to be the term's title */
3149 strncpy(term_menu
->title
, t
->name
, 12);
3151 /* Now set the ticks in the Windows> submenu (cuz it's easy) */
3152 mp
= wind_menu
; /* Windows submenu */
3153 mi
= (menu_item
*) (mp
+ 1); /* First entry */
3154 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
3156 Wimp_GetWindowState(data
[i
].w
, &ws
);
3157 mi
[i
].menuflags
.data
.ticked
= ws
.flags
.data
.open
;
3161 | Now, the tricky bit: find out which font is selected in this
3162 | term and tick it in the menu. Untick all the rest.
3164 set_font_menu_ticks(font_menu
, t
->font
->name
, "");
3166 /* Shade the 'Save>' entry if saving isn't possible (yet) */
3167 if (game_in_progress
&& character_generated
)
3168 Menu_SetFlags(term_menu
, TERM_MENU_SAVE
, 0, PDEADCHK
);
3170 Menu_SetFlags(term_menu
, TERM_MENU_SAVE
, 0, TRUE
);
3173 * Shade the resize entry if Term->fixed_shape is set, or if
3174 * bigscreen isn't supported
3176 if (BIGSCREEN
== FALSE
|| t
->t
.fixed_shape
)
3177 Menu_SetFlags(term_menu
, TERM_MENU_SIZE
, 0, TRUE
);
3179 Menu_SetFlags(term_menu
, TERM_MENU_SIZE
, 0, FALSE
);
3185 | Generic 'click' handler for windows - turns a drag on the window
3186 | into a move-window style drag.
3188 static BOOL
Hnd_Click(event_pollblock
* pb
, void *ref
)
3191 if (pb
->data
.mouse
.window
== data
[0].w
)
3193 if (pb
->data
.mouse
.button
.data
.select
)
3197 wimp_point clickpoint
= pb
->data
.mouse
.pos
;
3198 convert_block convert
;
3200 set_up_zrb(&data
[0]);
3202 fw
= zrb
.r_charw
<< screen_eig
.x
;
3203 fh
= zrb
.r_charh
<< screen_eig
.y
;
3204 if (zrb
.r_flags
.bits
.double_height
)
3209 /* SO fw & fh are in OS units here */
3210 Window_GetCoords(data
[0].w
, &convert
);
3211 Coord_PointToWorkArea(&clickpoint
, &convert
);
3213 xpos
= clickpoint
.x
/ fw
;
3214 ypos
= -clickpoint
.y
/ fh
;
3216 Term_mousepress(xpos
, ypos
, 1);
3220 else if (pb
->data
.mouse
.button
.data
.dragselect
||
3221 pb
->data
.mouse
.button
.data
.dragadjust
)
3224 b
.window
= pb
->data
.mouse
.window
;
3225 b
.screenrect
.min
.x
= b
.screenrect
.min
.y
= 0;
3226 b
.screenrect
.max
.x
= screen_size
.x
;
3227 b
.screenrect
.max
.y
= screen_size
.y
;
3228 b
.type
= drag_MOVEWINDOW
;
3238 | Handle a click on a Term window.
3240 static BOOL
Hnd_TermClick(event_pollblock
* pb
, void *ref
)
3242 term_data
*t
= (term_data
*)ref
;
3244 if (pb
->data
.mouse
.button
.data
.menu
)
3247 set_up_term_menu(t
);
3248 Menu_Show(term_menu
, pb
->data
.mouse
.pos
.x
- 32,
3249 pb
->data
.mouse
.pos
.y
+ 32);
3260 #endif /* !FULLSCREEN_ONLY */
3264 static void mark_ood(term_data
*t
, int minx
, int miny
, int maxx
, int maxy
)
3266 if (t
->changed_box
.min
.x
> minx
)
3267 t
->changed_box
.min
.x
= minx
;
3268 if (t
->changed_box
.max
.x
< maxx
)
3269 t
->changed_box
.max
.x
= maxx
;
3270 if (t
->changed_box
.min
.y
> miny
)
3271 t
->changed_box
.min
.y
= miny
;
3272 if (t
->changed_box
.max
.y
< maxy
)
3273 t
->changed_box
.max
.y
= maxy
;
3277 #ifndef FULLSCREEN_ONLY
3279 /* Check for an event (ie. key press) */
3280 static errr
Term_xtra_acn_check(void)
3282 static int last_poll
= 0;
3283 unsigned int curr_time
;
3287 | Only poll the wimp if there's something in the keyboard buffer
3288 | or every 10cs. This is presumably so that we process as many
3289 | keypresses as possible before any other application gets a go.
3292 /* Check the kbd buffer */
3293 SWI(3, 3, SWI_OS_Byte
, 128, 255, 0, /**/ NULL
, &bl
, &bh
);
3294 bl
= (bl
& 0xff) + (bh
<< 8);
3296 /* Check how long it is since we last polled */
3297 curr_time
= Time_Monotonic();
3299 if ((bl
> 0 && got_caret
) || ((curr_time
- last_poll
) > 9))
3301 last_poll
= curr_time
;
3308 | This allows the user to interrupt the borg.
3310 if (key_pressed
) return key_pressed
= 0;
3317 | Wait for an event (ie. keypress)
3318 | Note that we idle poll once a second to allow us to implement the
3321 static errr
Term_xtra_acn_event(void)
3325 while (!key_pressed
&& !fullscreen_font
)
3327 Event_PollIdle(100);
3331 return key_pressed
= 0;
3336 /* React to changes (eg. palette change) */
3337 static errr
Term_xtra_acn_react(void)
3343 /* Mark the entirety of each window as out of date */
3344 for (c
= 0; c
< MAX_TERM_DATA
; c
++)
3346 mark_ood(&data
[c
], 0, 0, data
[c
].t
.wid
, data
[c
].t
.hgt
);
3349 /* Force a redraw of the windows */
3356 #endif /* FULLSCREEN_ONLY */
3358 /* Do various things to a term */
3359 static errr
Term_xtra_acn(int n
, int v
)
3361 term_data
*t
= (term_data
*)Term
;
3365 /* Clear the Term */
3366 case TERM_XTRA_CLEAR
:
3368 #ifndef FULLSCREEN_ONLY
3369 if (fullscreen_font
)
3372 if (t
== (&data
[0])) Term_xtra_acn_clearFS();
3373 #ifndef FULLSCREEN_ONLY
3377 mark_ood(t
, 0, 0, Term
->wid
, Term
->hgt
);
3383 /* Wait/check for an event */
3384 case TERM_XTRA_EVENT
:
3386 #ifndef FULLSCREEN_ONLY
3387 if (fullscreen_font
)
3390 Term_xtra_acn_eventFS(v
);
3391 #ifndef FULLSCREEN_ONLY
3395 if (v
) return Term_xtra_acn_event();
3396 else return Term_xtra_acn_check();
3402 case TERM_XTRA_BORED
:
3404 #ifndef FULLSCREEN_ONLY
3405 if (fullscreen_font
)
3407 Term_xtra_acn_eventFS(0);
3408 #ifndef FULLSCREEN_ONLY
3409 else return Term_xtra_acn_check();
3414 case TERM_XTRA_FLUSH
:
3416 #ifndef FULLSCREEN_ONLY
3417 if (fullscreen_font
|| got_caret
)
3420 /* 1.21 - Hack: wait until no keys are pressed */
3424 while (v
!= 0xff) SWI(1, 2, SWI_OS_Byte
, 122, 0, &v
);
3427 /* Flush Kbd buffer */
3428 SWI(3, 0, SWI_OS_Byte
, 21, 0, 0);
3429 #ifndef FULLSCREEN_ONLY
3436 case TERM_XTRA_FRESH
:
3438 #ifndef FULLSCREEN_ONLY
3439 if (!fullscreen_font
) refresh_window(t
);
3444 /* Ensure line 'v' is plotted */
3445 case TERM_XTRA_FROSH
:
3447 /* Doesn't do anything */
3451 /* Set cursor visibility */
3452 case TERM_XTRA_SHAPE
:
3454 #ifndef FULLSCREEN_ONLY
3455 if (fullscreen_font
)
3458 if (t
== (&data
[0]))
3460 t
->cursor
.visible
= v
;
3462 draw_cursor(t
->cursor
.pos
.x
, t
->cursor
.pos
.y
);
3464 redraw_areaFS(t
->cursor
.pos
.x
, t
->cursor
.pos
.y
, 1, 1);
3466 #ifndef FULLSCREEN_ONLY
3470 t
->cursor
.visible
= v
? TRUE
: FALSE
;
3471 mark_ood(t
, t
->cursor
.pos
.x
, t
->cursor
.pos
.y
,
3472 t
->cursor
.pos
.x
+ 1, t
->cursor
.pos
.y
+ 1);
3474 refresh_window(t
); /* needed? */
3481 case TERM_XTRA_NOISE
:
3487 /* React to, eg. palette changes */
3488 case TERM_XTRA_REACT
:
3490 #ifndef FULLSCREEN_ONLY
3491 if (fullscreen_font
)
3494 return Term_xtra_acn_reactFS(FALSE
);
3495 #ifndef FULLSCREEN_ONLY
3499 return Term_xtra_acn_react();
3504 /* Delay for 'v' ms */
3505 case TERM_XTRA_DELAY
:
3509 unsigned int start
= Time_Monotonic();
3511 /* Round to nearest cs */
3514 /* Wait for vsync for the hell of it. */
3516 while ((Time_Monotonic() - start
) < v
);
3522 * This is used by ToME2, and presumably will never be picked up by other
3523 * variants, so it should be safe to #ifdef out like so:
3525 #ifdef TERM_XTRA_SCANSUBDIR
3526 /* Subdirectory scan */
3527 case TERM_XTRA_SCANSUBDIR
:
3529 filing_dirdata directory
;
3530 filing_direntry
*entry
;
3534 if (Filing_OpenDir(riscosify_name(scansubdir_dir
), &directory
, sizeof(filing_direntry
), readdirtype_DIRENTRY
) != NULL
)
3536 Error_Report(0, "Couldn't open directory \"%s\"", riscosify_name(scansubdir_dir
));
3540 while ((entry
= Filing_ReadDir(&directory
)) != NULL
)
3542 if (entry
->objtype
== filing_DIRECTORY
)
3544 string_free(scansubdir_result
[scansubdir_max
]);
3545 scansubdir_result
[scansubdir_max
] = string_make(entry
->name
);
3550 Filing_CloseDir(&directory
);
3554 #endif /* TERM_XTRA_SCANSUBDIR */
3558 * This is used by ToME, and presumably will never be picked up by other
3559 * variants, so it should be safe to #ifdef out like so:
3561 #ifdef TERM_XTRA_GET_DELAY
3562 /* Return current "time" in milliseconds */
3563 case TERM_XTRA_GET_DELAY
:
3565 Term_xtra_long
= Time_Monotonic() * 100;
3569 #endif /* TERM_XTRA_GET_DELAY */
3572 * This is used by ToME, and presumably will never be picked up by other
3573 * variants, so it should be safe to #ifdef out like so:
3575 #ifdef TERM_XTRA_RENAME_MAIN_WIN
3576 #ifndef FULLSCREEN_ONLY
3577 /* Rename main window */
3578 case TERM_XTRA_RENAME_MAIN_WIN
:
3580 Window_SetTitle(data
[0].w
, angband_term_name
[0]);
3583 #endif /* FULLSCREEN_ONLY */
3584 #endif /* TERM_XTRA_RENAME_MAIN_WIN */
3587 return 1; /* Unsupported */
3592 #ifndef FULLSCREEN_ONLY
3595 /* Move (but don't necessarily display) the cursor */
3596 static errr
Term_curs_acn(int x
, int y
)
3598 term_data
*t
= (term_data
*)Term
;
3600 if (t
->cursor
.visible
)
3601 mark_ood(t
, t
->cursor
.pos
.x
, t
->cursor
.pos
.y
,
3602 t
->cursor
.pos
.x
+ 1, t
->cursor
.pos
.y
+ 1);
3604 t
->cursor
.pos
.x
= x
;
3605 t
->cursor
.pos
.y
= y
;
3607 if (t
->cursor
.visible
)
3608 mark_ood(t
, t
->cursor
.pos
.x
, t
->cursor
.pos
.y
,
3609 t
->cursor
.pos
.x
+ 1, t
->cursor
.pos
.y
+ 1);
3617 | NB: these two are very simple since we use the Term's contents
3618 | directly to generate the r_data for ZapRedraw.
3621 /* Erase 'n' characters at (x,y) */
3622 static errr
Term_wipe_acn(int x
, int y
, int n
)
3624 mark_ood((term_data
*)Term
, x
, y
, x
+ n
, y
+ 1);
3628 /* Write 'n' characters from 's' with attr 'a' at (x,y) */
3629 static errr
Term_text_acn(int x
, int y
, int n
, byte a
, cptr s
)
3631 mark_ood((term_data
*)Term
, x
, y
, x
+ n
, y
+ 1);
3635 #endif /* !FULLSCREEN_ONLY */
3638 /* Initialise one of our terms */
3639 static void Term_init_acn(term
*t
)
3641 term_data
*term
= (term_data
*)t
;
3643 /* Ludicrous changed box settings :) */
3644 term
->changed_box
.min
.x
= 256;
3645 term
->changed_box
.min
.y
= 256;
3646 term
->changed_box
.max
.x
= 0;
3647 term
->changed_box
.max
.y
= 0;
3652 static void term_data_link(term_data
*td
, int k
)
3656 /* Initialise the term */
3657 term_init(t
, 80, 24, k
);
3659 /* Set flags and hooks */
3660 t
->attr_blank
= TERM_WHITE
;
3661 t
->char_blank
= ' ';
3663 /* Experiment (FS mode requires them) */
3664 t
->always_text
= TRUE
;
3665 t
->never_frosh
= TRUE
;
3666 /* Experiment (FS mode requires them) */
3668 #ifdef FULLSCREEN_ONLY
3669 t
->wipe_hook
= Term_wipe_acnFS
;
3670 t
->xtra_hook
= Term_xtra_acnFS
;
3671 t
->curs_hook
= Term_curs_acnFS
;
3672 t
->text_hook
= Term_text_acnFS
;
3674 t
->init_hook
= Term_init_acn
;
3675 t
->xtra_hook
= Term_xtra_acn
;
3676 t
->wipe_hook
= Term_wipe_acn
;
3677 t
->curs_hook
= Term_curs_acn
;
3678 t
->text_hook
= Term_text_acn
;
3679 t
->user_hook
= Term_user_acn
;
3680 #endif /* FULLSCREEN_ONLY */
3688 #ifndef FULLSCREEN_ONLY
3690 /* Open default windows (ie. as set in choices) at the appropriate sizes */
3691 static void show_windows(void)
3694 for (i
= MAX_TERM_DATA
; i
-- > 0;)
3696 if (!data
[i
].unopened
)
3698 if (data
[i
].def_open
)
3699 Window_Show(data
[i
].w
, open_WHEREVER
);
3703 if (data
[i
].def_open
)
3705 window_openblock ob
;
3706 ob
.window
= data
[i
].w
;
3707 ob
.screenrect
= data
[i
].def_pos
;
3708 ob
.scroll
= data
[i
].def_scroll
;
3710 Wimp_OpenWindow(&ob
);
3711 data
[i
].unopened
= 0;
3719 | 'ref' is used to indicate whether this close is being forced by some other
3720 | part of the code (eg. the Windows> submenu code). This is used to modify
3721 | the 'adjust doesn't close other terms' behavior.
3724 static BOOL
Hnd_MainClose(event_pollblock
* pb
, void *ref
)
3730 /* New in 1.08: don't close other Terms if closed with adjust */
3731 Wimp_GetPointerInfo(&mb
);
3732 if (ref
|| mb
.button
.data
.adjust
)
3734 Wimp_CloseWindow(data
[0].w
);
3738 /* Close all the terms, but mark the open ones as 'def_open' */
3739 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
3741 Wimp_GetWindowState(data
[i
].w
, &ws
);
3742 if (!ws
.flags
.data
.open
)
3744 data
[i
].def_open
= 0;
3748 Wimp_CloseWindow(data
[i
].w
);
3749 data
[i
].def_open
= 1;
3758 static BOOL
Hnd_PaletteChange(event_pollblock
* pb
, void *ref
)
3766 static BOOL
Hnd_ModeChange(event_pollblock
* pb
, void *ref
)
3769 Screen_CacheModeInfo();
3770 set_up_zrb_for_mode(); /* (re)set up the redraw block */
3771 cache_palette(); /* (re)cache the palette */
3772 cache_fonts(); /* (re)cache the fonts */
3774 /* Enforce sizes (eg. if screen_eig.y has changed) */
3775 for (i
= 0; i
< MAX_TERM_DATA
; i
++) force_term_resize(&(data
[i
]));
3783 static BOOL
Hnd_Keypress(event_pollblock
* pb
, void *ref
)
3785 static const char hex
[] = "0123456789ABCDEF";
3786 int c
= pb
->data
.key
.code
;
3787 /* Check whether this key was pressed in Term 0 */
3788 if (pb
->data
.key
.caret
.window
== data
[0].w
)
3793 case keycode_SHIFT_F12
:
3794 case keycode_CTRL_F12
:
3795 case keycode_CTRL_SHIFT_F12
:
3796 /* Never intercept these */
3799 case 27: /* handle escape specially */
3800 if (Kbd_KeyDown(inkey_CTRL
))
3806 /* Send everything else onto the Term package */
3808 /* Take care of "special" keypresses */
3817 case keycode_PAGEUP
:
3823 case keycode_PAGEDOWN
:
3841 /* Pass to the angband engine */
3842 /* Allow shift & ctrl to modify the keypad keys */
3843 if (c
>= '0' && c
<= '9')
3845 kbd_modifiers m
= Kbd_GetModifiers(FALSE
);
3854 /* Could maybe add ALT as 0x1000 ??? */
3857 /* Keys >255 have to be send as escape sequences (31=escape) */
3858 if (c
> 255 || c
== 31)
3861 Term_keypress(hex
[(c
& 0xf00) >> 8]);
3862 Term_keypress(hex
[(c
& 0x0f0) >> 4]);
3863 Term_keypress(hex
[(c
& 0x00f)]);
3868 /*if ( c==27 ) { escape_pressed = 1; } */
3878 /*--------------------------------------------------------------------------*/
3879 /* Gamma correction window stuff */
3880 /*--------------------------------------------------------------------------*/
3882 static void redraw_gamma(window_redrawblock
* rb
, BOOL
*more
)
3888 bx
= Coord_XToScreen(GC_XOFF
, (convert_block
*) & (rb
->rect
));
3889 by
= Coord_YToScreen(GC_YOFF
, (convert_block
*) & (rb
->rect
));
3898 for (i
= 0; i
< 16; i
++)
3901 for (dither
= 0; dither
< 2; dither
++)
3904 ColourTrans_SetGCOL(palette
[i
], dither
<< 8, 0);
3905 GFX_RectangleFill(x
, y
, w
, -h
);
3908 ColourTrans_SetGCOL(palette
[0], dither
<< 8, 0);
3909 GFX_RectangleFill(x
, y
, w
, -h
);
3910 ColourTrans_SetGCOL(palette
[i
], dither
<< 8, 0);
3911 GFX_RectangleFill(x
+ (w
/ 2) - 2, y
- (h
/ 2), 2, 2);
3916 Wimp_GetRectangle(rb
, more
);
3921 static void update_gamma(void)
3923 window_redrawblock rb
;
3926 rb
.window
= gamma_win
;
3927 rb
.rect
.min
.x
= GC_XOFF
;
3928 rb
.rect
.min
.y
= GC_YOFF
- GC_HEIGHT
;
3929 rb
.rect
.max
.y
= GC_XOFF
+ GC_WIDTH
+ screen_delta
.x
;
3930 rb
.rect
.max
.y
= GC_YOFF
+ screen_delta
.y
;
3932 Wimp_UpdateWindow(&rb
, &more
);
3933 if (more
) redraw_gamma(&rb
, &more
);
3938 static BOOL
Hnd_RedrawGamma(event_pollblock
* pb
, void *ref
)
3940 window_redrawblock rb
;
3943 rb
.window
= pb
->data
.openblock
.window
;
3944 Wimp_RedrawWindow(&rb
, &more
);
3945 if (more
) redraw_gamma(&rb
, &more
);
3951 static BOOL
Hnd_GammaClick(event_pollblock
* pb
, void *ref
)
3953 int up
= (ref
== 0);
3960 Icon_SetDouble(gamma_win
, 0, (double) gamma
/ 100, 2);
3962 Term_xtra_acn_react();
3970 Icon_SetDouble(gamma_win
, GAMMA_ICN
, (double) gamma
/ 100, 2);
3972 Term_xtra_acn_react();
3976 /* Hack: if the user menu is active then force it to redraw */
3977 if (user_menu_active
)
3987 | Reflect the current options in the gamma window
3989 static void set_gamma_window_state(void)
3991 if (minimise_memory
) return;
3993 Icon_SetDouble(gamma_win
, 0, (double) gamma
/ 100, 2);
3997 static void init_gamma_window(void)
3999 if (minimise_memory
) return;
4001 gamma_win
= Window_Create("gamma", template_TITLEMIN
);
4002 Event_Claim(event_REDRAW
, gamma_win
, event_ANY
, Hnd_RedrawGamma
, 0);
4003 Event_Claim(event_CLICK
, gamma_win
, GAMMA_DOWN
, Hnd_GammaClick
, (void *)1);
4004 Event_Claim(event_CLICK
, gamma_win
, GAMMA_UP
, Hnd_GammaClick
, (void *)0);
4005 set_gamma_window_state();
4009 /*--------------------------------------------------------------------------*/
4010 /* Sound options window stuff */
4011 /*--------------------------------------------------------------------------*/
4013 static slider_info volume_slider
;
4017 | Reflect the current sound config in the sound options window
4019 static void set_sound_window_state(void)
4021 if (minimise_memory
) return;
4023 Icon_SetSelect(sound_win
, SND_ENABLE
, enable_sound
);
4024 Slider_SetValue(&volume_slider
, sound_volume
, NULL
, NULL
);
4026 if (sound_volume
> 127)
4027 volume_slider
.colour
.foreground
= colour_RED
;
4029 volume_slider
.colour
.foreground
= colour_GREEN
;
4035 | The sound slider has been dragged, so update the sound volume setting
4037 static int update_volume_from_slider(slider_info
*si
, void *ref
)
4039 sound_volume
= Slider_ReadValue(si
);
4041 if (sound_volume
> 127)
4042 volume_slider
.colour
.foreground
= colour_RED
;
4044 volume_slider
.colour
.foreground
= colour_GREEN
;
4051 | Handle redraw events for the sound options window
4053 static BOOL
Hnd_RedrawSnd(event_pollblock
* pb
, void *ref
)
4055 window_redrawblock redraw
;
4058 redraw
.window
= pb
->data
.openblock
.window
;
4059 Wimp_RedrawWindow(&redraw
, &more
);
4063 Slider_Redraw(((slider_info
*) ref
), &redraw
.cliprect
);
4064 Wimp_GetRectangle(&redraw
, &more
);
4071 | Handle clicks on the sound options window
4073 static BOOL
Hnd_SndClick(event_pollblock
* pb
, void *ref
)
4075 int icn
= pb
->data
.mouse
.icon
;
4076 int adj
= pb
->data
.mouse
.button
.data
.adjust
;
4077 slider_info
*si
= (slider_info
*) ref
;
4081 /* Bump arrows for the slider: */
4087 sound_volume
+= adj
;
4088 if (sound_volume
< SOUND_VOL_MIN
)
4090 sound_volume
= SOUND_VOL_MIN
;
4092 if (sound_volume
> SOUND_VOL_MAX
)
4094 sound_volume
= SOUND_VOL_MAX
;
4096 set_sound_window_state();
4099 /* The slider itself */
4100 case SND_VOL_SLIDER
:
4101 Icon_ForceRedraw(sound_win
, SND_VOL_SLIDER
);
4102 Slider_Drag(si
, NULL
, NULL
, NULL
);
4105 /* The enable/disable icon */
4107 enable_sound
= !enable_sound
;
4108 Icon_SetSelect(sound_win
, SND_ENABLE
, enable_sound
);
4116 /* Hack: if the user menu is active then force it to redraw */
4117 if (user_menu_active
)
4129 | Set the sound options window up, ready to rock :)
4131 static void init_sound_window(void)
4133 sound_win
= Window_Create("sound", template_TITLEMIN
);
4135 Event_Claim(event_REDRAW
, sound_win
, event_ANY
, Hnd_RedrawSnd
,
4136 (void *)&volume_slider
);
4137 Event_Claim(event_CLICK
, sound_win
, event_ANY
, Hnd_SndClick
,
4138 (void *)&volume_slider
);
4140 /* Set up the slider info */
4141 volume_slider
.window
= sound_win
;
4142 volume_slider
.icon
= SND_VOL_SLIDER
;
4143 volume_slider
.limits
.min
= SOUND_VOL_MIN
;
4144 volume_slider
.limits
.max
= SOUND_VOL_MAX
;
4145 volume_slider
.colour
.foreground
= colour_GREEN
;
4146 volume_slider
.colour
.background
= colour_WHITE
;
4147 volume_slider
.border
.x
= 8;
4148 volume_slider
.border
.y
= 8;
4149 volume_slider
.update
= update_volume_from_slider
;
4151 set_sound_window_state();
4158 /*--------------------------------------------------------------------------*/
4171 | A font has been selected.
4172 | At this point, menu_term is a pointer to the term for which the
4175 static void handle_font_selection(int *s
)
4180 menu_ptr mp
= font_menu
;
4183 /* Follow the >s to the entry specified */
4184 for (mis
= s
; *mis
!= -1; mis
++)
4185 mp
= ((menu_item
*) (mp
+ 1))[*mis
].submenu
.menu
;
4188 | Now, check to see if we've hit a leaf entry.
4189 | NB: If the entry isn't a leaf entry then the first entry in its submenu
4192 if (((int)mp
) != -1)
4196 mp
= ((menu_item
*) (mp
+ 1))[0].submenu
.menu
;
4199 if (((int)mp
) != -1)
4202 e
= Wimp_DecodeMenu(font_menu
, s
, name
);
4209 /* Make sure that the string is NULL terminated */
4210 for (r
= name
; *r
>= ' '; r
++)
4214 attach_font_to_term(menu_term
, name
);
4215 mark_ood(menu_term
, 0, 0, menu_term
->t
.wid
, menu_term
->t
.hgt
);
4216 refresh_window(menu_term
);
4220 #endif /* FULLSCREEN_ONLY */
4225 static void load_choices(void)
4231 int choices_version
= 0;
4233 cf
= find_choices(FALSE
);
4235 fp
= fopen(cf
, "r");
4237 /* Implement default choices */
4238 data
[0].def_open
= 1;
4239 data
[0].unopened
= 1; /* ie. force def_pos */
4240 data
[0].def_pos
.min
.x
= (screen_size
.x
- 1280) / 2;
4241 data
[0].def_pos
.max
.x
= (screen_size
.x
+ 1280) / 2;
4242 data
[0].def_pos
.min
.y
= (screen_size
.y
- 768) / 2 - 32;
4243 data
[0].def_pos
.max
.y
= (screen_size
.y
+ 768) / 2 - 32;
4244 data
[0].def_scroll
.x
= data
[0].def_scroll
.y
= 0;
4245 for (i
= 1; i
< MAX_TERM_DATA
; i
++)
4247 data
[i
].def_open
= 0;
4248 data
[i
].unopened
= 1; /* ie. force def_pos */
4249 data
[i
].def_pos
.min
.x
= (screen_size
.x
- 1280) / 2;
4250 data
[i
].def_pos
.max
.x
= (screen_size
.x
+ 1280) / 2;
4251 data
[i
].def_pos
.min
.y
= (screen_size
.y
- 768) / 2;
4252 data
[i
].def_pos
.max
.y
= (screen_size
.y
+ 768) / 2;
4253 data
[i
].def_scroll
.x
= data
[i
].def_scroll
.y
= 0;
4261 if (!fgets(buffer
, sizeof(buffer
), fp
))
4267 if (memcmp(buffer
, "[Angband config, Musus' port]\n", 30) == 0)
4269 choices_version
= 1;
4271 else if (memcmp(buffer
, "[Angband config v2, Musus' port]\n", 33) == 0)
4273 choices_version
= 2;
4276 if (choices_version
== 0)
4283 while (fgets(buffer
, sizeof(buffer
), fp
))
4285 t_
= strtok(buffer
, " "); /* Term number (or keyword, "Gamma", etc.) */
4286 o_
= strtok(NULL
, "\n"); /* argument string */
4290 } /* missing (or null) argument? */
4293 if (!strcmp(t_
, "Gamma"))
4294 gamma
= atof(o_
) * 100;
4295 else if (!strcmp(t_
, "Monochrome"))
4296 force_mono
= !strcmp(o_
, "on");
4297 else if (!strcmp(t_
, "Sound"))
4298 enable_sound
= !strcmp(o_
, "on");
4299 else if (!strcmp(t_
, "Volume"))
4300 sound_volume
= atoi(o_
);
4301 else if (!strcmp(t_
, "FullScreen"))
4302 start_fullscreen
= !strcmp(o_
, "on");
4303 else if (!strcmp(t_
, "Hourglass"))
4304 use_glass
= !strcmp(o_
, "on");
4305 else if (!strcmp(t_
, "HackFlush"))
4306 hack_flush
= !strcmp(o_
, "on");
4307 else if (!strcmp(t_
, "AlarmTimeH"))
4309 else if (!strcmp(t_
, "AlarmTimeM"))
4311 else if (!strcmp(t_
, "AlarmText"))
4312 strcpy(alarm_message
, o_
);
4313 else if (!strcmp(t_
, "AlarmBeep"))
4314 alarm_beep
= !strcmp(o_
, "on");
4315 else if (!strcmp(t_
, "AlarmType"))
4318 for (i
= 0; i
< 4; i
++)
4319 if (!strcmp(alarm_types
[i
], o_
))
4322 else if (isdigit((unsigned char)*t_
))
4325 if (t
>= 0 && t
< MAX_TERM_DATA
)
4327 char *f
, *x0
, *y0
, *x1
, *y1
, *sx
, *sy
, *dx
= NULL
, *dy
= NULL
;
4328 o_
= strtok(o_
, " "); /* first word */
4329 f
= strtok(NULL
, " "); /* font name */
4330 x0
= strtok(NULL
, " "); /* x posn (min) */
4331 y0
= strtok(NULL
, " "); /* y posn (min) */
4332 x1
= strtok(NULL
, " "); /* x posn (max) */
4333 y1
= strtok(NULL
, " "); /* y posn (max) */
4334 sx
= strtok(NULL
, " "); /* x scroll offset */
4336 if (choices_version
== 1)
4338 sy
= strtok(NULL
, "\n"); /* y scroll offset */
4342 sy
= strtok(NULL
, " "); /* y scroll offset */
4343 dx
= strtok(NULL
, " "); /* width */
4344 dy
= strtok(NULL
, " "); /* height */
4347 data
[t
].def_open
= (t
== 0) || atoi(o_
);
4348 data
[t
].def_pos
.min
.x
= atoi(x0
);
4349 data
[t
].def_pos
.min
.y
= atoi(y0
);
4350 data
[t
].def_pos
.max
.x
= atoi(x1
);
4351 data
[t
].def_pos
.max
.y
= atoi(y1
);
4352 data
[t
].def_scroll
.x
= atoi(sx
);
4353 data
[t
].def_scroll
.y
= atoi(sy
);
4354 data
[t
].unopened
= 1; /* ie. force def_pos */
4355 #ifndef FULLSCREEN_ONLY
4356 /* Ensure we have size before setting it. */
4359 term_change_size(&data
[t
], atoi(dx
), atoi(dy
));
4362 attach_font_to_term(&(data
[t
]), f
);
4363 #endif /* FULLSCREEN_ONLY */
4375 static void save_choices(void)
4382 write_alarm_choices();
4384 cf
= find_choices(TRUE
);
4387 plog("Failed to locate writable choices file!");
4391 fp
= fopen(cf
, "w");
4394 plog("Can't write choices file");
4398 fpm
= fopen(find_choices_mirror(), "w");
4400 f2printf(fp
, fpm
, "[Angband config v2, Musus' port]\n");
4401 f2printf(fp
, fpm
, "Gamma %.2lf\n", (double) gamma
/ 100);
4402 f2printf(fp
, fpm
, "Monochrome %s\n", force_mono
? "on" : "off");
4403 f2printf(fp
, fpm
, "Sound %s\n", enable_sound
? "on" : "off");
4404 f2printf(fp
, fpm
, "Volume %d\n", sound_volume
);
4405 f2printf(fp
, fpm
, "FullScreen %s\n", start_fullscreen
? "on" : "off");
4406 f2printf(fp
, fpm
, "Hourglass %s\n", use_glass
? "on" : "off");
4407 f2printf(fp
, fpm
, "HackFlush %s\n", hack_flush
? "on" : "off");
4409 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
4412 Wimp_GetWindowState(data
[i
].w
, &ws
);
4413 f2printf(fp
, fpm
, "%d %d %s ", i
, ws
.flags
.data
.open
,
4414 data
[i
].font
->name
);
4415 f2printf(fp
, fpm
, "%d ", ws
.openblock
.screenrect
.min
.x
);
4416 f2printf(fp
, fpm
, "%d ", ws
.openblock
.screenrect
.min
.y
);
4417 f2printf(fp
, fpm
, "%d ", ws
.openblock
.screenrect
.max
.x
);
4418 f2printf(fp
, fpm
, "%d ", ws
.openblock
.screenrect
.max
.y
);
4419 f2printf(fp
, fpm
, "%d %d ", ws
.openblock
.scroll
.x
,
4420 ws
.openblock
.scroll
.y
);
4421 f2printf(fp
, fpm
, "%d %d\n", data
[i
].t
.wid
, data
[i
].t
.hgt
);
4433 | Update the Alarm choices file to reflect changed alarm settings.
4435 static void write_alarm_choices(void)
4440 /* Open the choices file for reading */
4441 cf
= find_alarmfile(TRUE
);
4444 plog("Can't determine Alarm file location!");
4448 fp
= fopen(cf
, "w");
4451 plog("Can't write Alarm file");
4455 /* Write the new alarm options */
4456 fprintf(fp
, "AlarmType %s\n", alarm_types
[alarm_type
]);
4457 fprintf(fp
, "AlarmTimeH %d\n", alarm_h
);
4458 fprintf(fp
, "AlarmTimeM %d\n", alarm_m
);
4459 fprintf(fp
, "AlarmText %s\n", alarm_message
);
4460 fprintf(fp
, "AlarmBeep %s\n", alarm_beep
? "on" : "off");
4466 | Read the Alarm choices file.
4468 static void read_alarm_choices(void)
4474 cf
= find_alarmfile(FALSE
);
4480 fp
= fopen(cf
, "r");
4483 const char *t_
, *o_
;
4485 while (fgets(buffer
, sizeof(buffer
), fp
))
4487 t_
= strtok(buffer
, " "); /* Keyword */
4488 o_
= strtok(NULL
, "\n"); /* argument string */
4492 } /* missing (or null) argument? */
4495 if (!strcmp(t_
, "AlarmTimeH"))
4497 else if (!strcmp(t_
, "AlarmTimeM"))
4499 else if (!strcmp(t_
, "AlarmText"))
4500 strcpy(alarm_message
, o_
);
4501 else if (!strcmp(t_
, "AlarmBeep"))
4502 alarm_beep
= !strcmp(o_
, "on");
4503 else if (!strcmp(t_
, "AlarmType"))
4506 for (i
= 0; i
< 4; i
++)
4507 if (!strcmp(alarm_types
[i
], o_
))
4518 #ifndef FULLSCREEN_ONLY
4520 | Handle selections from the term menu(s)
4522 static BOOL
Hnd_TermMenu(event_pollblock
* pb
, void *ref
)
4527 Wimp_GetPointerInfo(&mb
);
4529 switch (pb
->data
.selection
[0])
4531 case TERM_MENU_INFO
: /* Info> */
4533 case TERM_MENU_FONT
: /* Font> */
4534 /* Sub item selected? */
4535 if (pb
->data
.selection
[1] == -1)
4539 handle_font_selection(pb
->data
.selection
+ 1);
4541 case TERM_MENU_WINDOWS
: /* Windows> */
4542 if (pb
->data
.selection
[1] == -1)
4546 i
= pb
->data
.selection
[1];
4549 Wimp_GetWindowState(data
[i
].w
, &ws
);
4550 if (ws
.flags
.data
.open
)
4553 Hnd_MainClose(NULL
, (void *)TRUE
);
4555 Window_Hide(data
[i
].w
);
4566 if (!data
[i
].unopened
)
4568 Window_Show(data
[i
].w
, open_WHEREVER
);
4572 window_openblock ob
;
4573 ob
.window
= data
[i
].w
;
4574 ob
.screenrect
= data
[i
].def_pos
;
4575 ob
.scroll
= data
[i
].def_scroll
;
4576 ob
.behind
= -1; /* could use data[0].w; ? */
4577 Wimp_OpenWindow(&ob
);
4578 data
[i
].unopened
= 0;
4586 if (mb
.button
.data
.adjust
)
4588 set_up_term_menu(menu_term
);
4601 | Handle selections from the iconbar menu
4603 static BOOL
Hnd_IbarMenu(event_pollblock
* pb
, void *ref
)
4606 Wimp_GetPointerInfo(&mb
);
4608 switch (pb
->data
.selection
[0])
4610 case IBAR_MENU_INFO
: /* Info> */
4612 case IBAR_MENU_FULLSCREEN
: /* Full screen */
4613 /* Do Full Screen mode */
4614 enter_fullscreen_mode();
4616 case IBAR_MENU_GAMMA
: /* Gamma correction */
4618 case IBAR_MENU_SOUND
: /* Sound */
4620 | enable_sound = !enable_sound;
4621 | if ( enable_sound ) { initialise_sound(); }
4622 | Menu_SetFlags( ibar_menu, IBAR_MENU_SOUND, enable_sound, 0 );
4623 | set_sound_window_state();
4626 case IBAR_MENU_WINDOWS
: /* Windows> */
4628 | Hack: pass it off as the equivalent selection from
4631 pb
->data
.selection
[0] = TERM_MENU_WINDOWS
;
4632 return Hnd_TermMenu(pb
, ref
);
4634 case IBAR_MENU_SAVECHOICES
: /* Save choices */
4637 case IBAR_MENU_QUIT
: /* Quit */
4638 if (game_in_progress
&& character_generated
)
4642 save_player(SAVE_PLAYER_PARAM
);
4647 Msgs_Report(0, "err.nosave");
4653 if (mb
.button
.data
.adjust
)
4663 static BOOL
Hnd_MenuSel(event_pollblock
* pb
, void *ref
)
4665 if (menu_currentopen
== ibar_menu
)
4666 return Hnd_IbarMenu(pb
, ref
);
4667 else if (menu_currentopen
== term_menu
)
4668 return Hnd_TermMenu(pb
, ref
);
4673 static BOOL
Hnd_IbarClick(event_pollblock
* pb
, void *ref
)
4675 if (pb
->data
.mouse
.button
.data
.menu
)
4677 set_gamma_window_state();
4678 set_sound_window_state();
4680 /* Hack: shade the Save> option if appropriate */
4681 if (game_in_progress
&& character_generated
)
4682 Menu_SetFlags(ibar_menu
, IBAR_MENU_SAVE
, 0, PDEADCHK
);
4684 Menu_SetFlags(ibar_menu
, IBAR_MENU_SAVE
, 0, TRUE
);
4687 | Hack: set up the Term menu as if it was opened over the main
4688 | window (so that the Windows> submenu is set correctly)
4690 menu_term
= (term_data
*)&data
[0];
4691 set_up_term_menu(menu_term
);
4693 Menu_Show(ibar_menu
, pb
->data
.mouse
.pos
.x
, -1);
4697 if (pb
->data
.mouse
.button
.data
.select
)
4704 if (pb
->data
.mouse
.button
.data
.adjust
)
4706 enter_fullscreen_mode();
4716 * Handler for NULL events (should this check the alarm in the desktop?
4718 static BOOL
Hnd_null(event_pollblock
*event
, void *ref
)
4720 /* Really no need to check the alarm more than once per second. */
4721 if (alarm_type
&& Time_Monotonic() > alarm_lastcheck
+ 100)
4733 | Handler for PreQuit messages (eg. at shutdown).
4735 static BOOL
Hnd_PreQuit(event_pollblock
* b
, void *ref
)
4737 BOOL shutdown
= (b
->data
.message
.data
.words
[0] & 1) == 0;
4738 task_handle originator
= b
->data
.message
.header
.sender
;
4739 unsigned int quitref
;
4745 if (!(game_in_progress
&& character_generated
))
4746 return TRUE
; /* ignore, we're OK to die */
4748 /* Stop the shutdown/quit */
4749 memcpy(&mb
, &(b
->data
.message
), 24);
4750 quitref
= mb
.header
.yourref
;
4751 mb
.header
.yourref
= mb
.header
.myref
;
4752 Wimp_SendMessage(event_ACK
, &mb
, originator
, 0);
4755 | We handle this differently depending on the version of the Wimp;
4756 | newer versions give us much more flexibility.
4758 if (event_wimpversion
< 350)
4761 | Older versions - use 'OK' and 'Cancel'.
4762 | There is no "Save & Quit" button.
4764 Msgs_Lookup("err.shuttitl:Query from %s", e
.errmess
, 64);
4765 sprintf(buffer1
, e
.errmess
, VARIANT
);
4766 Msgs_Lookup("err.shutdown:Unsaved game; are you sure you want to quit?",
4769 SWI(3, 2, SWI_Wimp_ReportError
, &e
, 3 | 16, buffer1
, NULL
, &ok
);
4772 return TRUE
; /* no! Pleeeeeease don't kill leeeeddle ol' me! */
4777 | Newer version: can add buttons to the dialog.
4778 | we add a 'Save and Quit' button to allow the shutdown to
4779 | continue /after/ saving.
4784 Msgs_Lookup("err.shutbuts:Save & quit,Don't quit,Quit anyway",
4786 Msgs_Lookup("err.shuttitl:Query from %s", e
.errmess
, 64);
4787 sprintf(buffer1
, e
.errmess
, VARIANT
);
4788 Msgs_Lookup("err.shutdown:Unsaved game; are you sure you want to quit?",
4792 flags
= 0 | 16 | 256 | (4 << 9);
4794 SWI(6, 2, SWI_Wimp_ReportError
, &e
, flags
, buffer1
, ICONNAME
, 0,
4795 buttons
, NULL
, &ok
);
4798 return TRUE
; /* no! Pleeeeeease don't kill leeeeddle ol' me! */
4804 save_player(SAVE_PLAYER_PARAM
); /* Save & Quit */
4808 Msgs_Report(0, "err.nosave");
4815 /* RO2 doesn't use the shudown flag */
4816 if (shutdown
&& event_wimpversion
>= 300 && mb
.header
.size
>= 24)
4819 kb
.code
= 0x1fc; /* restart shutdown sequence */
4820 Wimp_SendMessage(event_KEY
, (message_block
*) & kb
, originator
, 0);
4823 /* "Time... to die." */
4826 return TRUE
; /* The one great certainty (sic) */
4829 #endif /* FULLSCREEN_ONLY */
4834 static void initialise_terms(void)
4839 #ifndef FULLSCREEN_ONLY
4840 if (!minimise_memory
)
4842 /* Create a window for each term. Term 0 is special (no scroll bars) */
4843 data
[0].w
= Window_Create("angband", template_TITLEMIN
);
4844 data
[0].font
= SYSTEM_FONT
;
4845 data
[0].def_open
= 1;
4846 data
[0].unopened
= 1;
4847 sprintf(t
, "%s %s", VARIANT
, VERSION
);
4848 Window_SetTitle(data
[0].w
, t
);
4849 strncpy(data
[0].name
, VARIANT
, 12);
4850 Event_Claim(event_KEY
, data
[0].w
, event_ANY
, Hnd_Keypress
,
4851 (void *)&(data
[0]));
4852 Event_Claim(event_REDRAW
, data
[0].w
, event_ANY
, Hnd_Redraw
,
4853 (void *)&(data
[0]));
4854 Event_Claim(event_CLICK
, data
[0].w
, event_ANY
, Hnd_TermClick
,
4855 (void *)&(data
[0]));
4856 Event_Claim(event_CLOSE
, data
[0].w
, event_ANY
, Hnd_MainClose
, NULL
);
4858 for (i
= 1; i
< MAX_TERM_DATA
; i
++)
4860 data
[i
].w
= Window_Create("term", template_TITLEMIN
);
4861 data
[i
].font
= SYSTEM_FONT
;
4862 data
[i
].def_open
= 0;
4863 data
[i
].unopened
= 1;
4864 #ifndef OLD_TERM_MENU
4865 sprintf(t
, "%s (%s %s)", TERM_NAME(i
), VARIANT
, VERSION
);
4867 sprintf(t
, "Term-%d (%s %s)", i
, VARIANT
, VERSION
);
4869 Window_SetTitle(data
[i
].w
, t
);
4870 strncpy(data
[i
].name
, t
, 12);
4871 Event_Claim(event_CLICK
, data
[i
].w
, event_ANY
, Hnd_TermClick
,
4872 (void *)&(data
[i
]));
4873 Event_Claim(event_REDRAW
, data
[i
].w
, event_ANY
, Hnd_Redraw
,
4874 (void *)&(data
[i
]));
4877 #endif /* FULLSCREEN_ONLY */
4879 term_data_link(&(data
[0]), 256);
4881 for (i
= 1; i
< MAX_TERM_DATA
; i
++)
4883 term_data_link(&(data
[i
]), 16);
4884 TERM(i
) = &(data
[i
].t
);
4887 TERM(0) = &(data
[0].t
);
4888 Term_activate(&(data
[0].t
));
4894 static unsigned int htoi(char *s
)
4896 static const char hex
[] = "0123456789ABCDEF";
4901 int d
= toupper((unsigned char)*s
++);
4907 v
= (v
<< 4) + (m
- hex
);
4912 static int read_unsigned(char *t
)
4915 if (SWI(2, 3, SWI_OS_ReadUnsigned
, 2, t
, NULL
, NULL
, &r
))
4921 | Scan the string at 'n', replacing dodgy characters with underbars
4923 static void sanitise_name(char *n
)
4927 if (strchr("\"$%^&*\\\'@#.,", *n
))
4934 | Ensure that the path to a given object exists.
4935 | Ie. if |p| = "a.b.c.d" then we attempt to
4936 | create directories a, a.b and a.b.c if they don't
4938 | Note that 'd' may be absent.
4940 static int ensure_path(char *p
)
4950 if (SWI(5, 0, SWI_OS_File
, 8, tmp
, 0, 0, 77))
4951 return 0; /* Eeek! */
4961 * Set up the Scrap, Choices and Alarm paths, trying for
4962 * Choices:blah...,etc. by preference, but falling back on lib/xtra
4965 static void init_paths(void)
4972 /* Form the sub-path we use for both Choices and Scrap dirs: */
4973 v
= subpath
+ sprintf(subpath
, "%s", VARIANT
);
4974 sanitise_name(subpath
);
4975 sprintf(v
, ".%s", VERSION
);
4976 sanitise_name(v
+ 1);
4978 /* Do the Scrap path first: */
4981 /* Try for Wimp$ScrapDir... */
4982 t
= getenv("Wimp$ScrapDir");
4985 sprintf(tmp
, "%s.AngbandEtc.%s.", t
, subpath
);
4986 if (ensure_path(tmp
))
4988 strcpy(scrap_path
, tmp
);
4992 /* Couldn't use Wimp$ScrapDir, so fall back on lib.xtra.scrap */
4995 sprintf(tmp
, "%sxtra.scrap.", resource_path
);
4996 if (ensure_path(tmp
))
4998 strcpy(scrap_path
, tmp
);
5002 /* Now set up the Choices and Alarm files: */
5004 /* Read only Choices file is always lib.xtra.Choices */
5005 sprintf(choices_file
[CHFILE_READ
], "%sXtra.Choices", resource_path
);
5006 /* Default writable Choices file is the same */
5007 strcpy(choices_file
[CHFILE_WRITE
], choices_file
[CHFILE_READ
]);
5008 /* No default mirror Choices file */
5009 strcpy(choices_file
[CHFILE_MIRROR
], "");
5011 /* Read only Alarm file is always lib.xtra.Alarm */
5012 sprintf(alarm_file
[CHFILE_READ
], "%sXtra.Alarm", resource_path
);
5013 /* Default writable Alarm file is the same */
5014 strcpy(alarm_file
[CHFILE_WRITE
], alarm_file
[CHFILE_READ
]);
5016 /* Try to use Choices$Path, etc. for the others... */
5018 t
= getenv("Choices$Write"); /* Ie. where choices should be written */
5022 sprintf(tmp
, "%s.AngbandEtc.%s", t
, subpath
);
5023 if (ensure_path(tmp
))
5025 /* Use for writable file: */
5026 strcpy(choices_file
[CHFILE_WRITE
], tmp
);
5027 /* Form 'mirror' filename: same path but with a fixed leafname */
5028 strcpy(v
+ 1, "Default");
5029 sprintf(tmp
, "%s.AngbandEtc.%s", t
, subpath
);
5030 strcpy(choices_file
[CHFILE_MIRROR
], tmp
);
5033 /* Alarm file (doesn't involve subpath) */
5034 sprintf(tmp
, "%s.AngbandEtc.Global.Alarm", t
);
5035 if (ensure_path(tmp
))
5037 /* Use for read/writable file */
5038 strcpy(alarm_file
[CHFILE_WRITE
], tmp
);
5050 * Return the appropriate (full) pathname.
5052 * For write ops, the read/write file is returned.
5054 * For read ops, either the read/write file, the mirror file,
5055 * or the read only file will be returned as appropriate.
5057 static char *find_choices(int write
)
5060 return choices_file
[CHFILE_WRITE
];
5062 if (File_Size(choices_file
[CHFILE_WRITE
]) > 0)
5063 return choices_file
[CHFILE_WRITE
];
5065 if (File_Size(choices_file
[CHFILE_MIRROR
]) > 0)
5066 return choices_file
[CHFILE_MIRROR
];
5068 return choices_file
[CHFILE_READ
];
5071 static char *find_choices_mirror(void)
5073 return choices_file
[CHFILE_MIRROR
];
5076 static char *find_alarmfile(int write
)
5079 return alarm_file
[CHFILE_WRITE
];
5081 if (File_Size(alarm_file
[CHFILE_WRITE
]) > 0)
5082 return alarm_file
[CHFILE_WRITE
];
5084 return alarm_file
[CHFILE_READ
];
5090 * Redefinable "core" action
5092 void (*core_aux
)(cptr
) = NULL
;
5095 * Dump a core file, after printing a warning message
5096 * As with "quit()", try to use the "core_aux()" hook first.
5102 /* Use the aux function */
5103 if (core_aux
) (*core_aux
)(str
);
5105 /* Dump the warning string */
5108 /* Attempt to Crash */
5109 (*crash
) = (*crash
);
5111 /* Be sure we exited */
5112 quit("core() failed");
5120 int main(int argc
, char *argv
[])
5124 char *arg_savefile
= 0;
5127 int da_font
= 1, da_game
= 1;
5130 atexit(final_acn
); /* "I never did care about the little things." */
5134 /* Parse arguments */
5135 for (i
= 1; i
< argc
; i
++)
5137 if (argv
[i
][0] == '-')
5139 switch (tolower((unsigned char)argv
[i
][1]))
5143 /* Minimise Memory */
5144 minimise_memory
= 1;
5149 case 'c': /* -c[a][s][f][<n>] */
5150 for (j
= 2; argv
[i
][j
]; j
++)
5152 int on
= isupper((unsigned char)argv
[i
][j
]);
5154 switch (tolower((unsigned char)argv
[i
][j
]))
5156 #ifdef ABBR_FILECACHE
5157 case 'a': abbr_filecache
=
5160 case 'f': abbr_tmpfile
=
5164 #ifdef SMART_FILECACHE
5165 case 's': smart_filecache
=
5170 case 'p': flush_scrap
=
5175 if (isdigit((unsigned char)argv
[i
][j
]))
5177 max_file_cache_size
=
5178 atoi(argv
[i
] + j
) << 10;
5179 while (isdigit((unsigned char)argv
[i
][++j
]))
5181 if (max_file_cache_size
<= 0)
5189 fprintf(stderr
, "Unrecognised option: -c%s",
5196 case 'w': /* -waitrelease */
5199 case 's': /* -s<savefile> */
5201 arg_savefile
= argv
[i
] + 2;
5203 case 'f': /* -fullscreen */
5206 case 'h': /* -hourglass */
5209 case 't': /* -T<filetype> */
5211 vfiletype
= htoi(argv
[i
] + 2);
5214 case 'd': /* -df, -dg, -dc or -d : disable DAs */
5215 switch (tolower((unsigned char)argv
[i
][2]))
5217 case 0: /* -d => disable both */
5218 da_font
= da_game
= 0;
5220 case 'f': /* -df => disable font only */
5223 case 'g': /* -dg => disable game only */
5229 case '%': /* -%<debug_opts> */
5231 int v
= read_unsigned(argv
[i
] + 2);
5232 log_g_malloc
= v
& 1;
5233 show_sound_alloc
= v
& 2;
5237 fprintf(stderr
, "Unrecognised option: %s", argv
[i
]);
5243 /* 1.27 - new handling of -minimise-memory: */
5244 #ifndef FULLSCREEN_ONLY
5245 if (minimise_memory
)
5246 #endif /* FULLSCREEN_ONLY */
5249 fs_quit_key_text
= "(fullscreen only mode)";
5252 init_memory(da_font
, da_game
); /* Set up dynamic areas, etc. if possible */
5254 /* Install memory allocation hooks */
5255 ralloc_aux
= g_malloc
;
5256 rnfree_aux
= g_free
;
5259 /* Install replacement error reporting routines */
5260 quit_aux
= quit_hook
;
5261 plog_aux
= plog_hook
;
5262 core_aux
= core_hook
;
5265 /* Hook in the file modification hook in scth*/
5266 check_modification_date_hook
= check_modification_date
;
5269 /* Expand the (Angband) resource path */
5270 t
= getenv(RISCOS_VARIANT
"$Path");
5271 if (!t
|| !*t
) Msgs_ReportFatal(0, "A resources path could not be formed.");
5272 strcpy(resource_path
, t
);
5274 /* Decide where scrap, choices and alarm files live: */
5277 /* Hack: if no savefile specified, use a default */
5280 arg_savefile
= malloc(strlen(resource_path
) + 32);
5283 Msgs_ReportFatal(0, "err.mem");
5285 sprintf(arg_savefile
, "%s%s", resource_path
, ">Save.Savefile");
5288 /* This crap appears here so that plog() will work properly before
5289 init_acn() is called... */
5290 Resource_Initialise(RISCOS_VARIANT
);
5291 Msgs_LoadFile("Messages");
5293 #ifndef FULLSCREEN_ONLY
5294 if (!minimise_memory
)
5296 Event_Initialise(RISCOS_VARIANT
);
5298 /* Load Templates */
5299 Template_Initialise();
5300 Template_LoadFile("Templates");
5302 #endif /* FULLSCREEN_ONLY */
5304 Screen_CacheModeInfo();
5306 /* Initialise some ZapRedraw stuff */
5307 initialise_palette();
5308 initialise_fonts(); /* Set up the fonts */
5309 #ifndef FULLSCREEN_ONLY
5311 if (!minimise_memory
)
5313 /* Initialise some Wimp specific stuff */
5314 init_gamma_window();
5315 init_sound_window();
5319 ibar_icon
= Icon_BarIcon(ICONNAME
, iconbar_RIGHT
);
5321 /* Global handlers */
5322 Event_Claim(event_OPEN
, event_ANY
, event_ANY
, Handler_OpenWindow
, NULL
);
5323 Event_Claim(event_CLOSE
, event_ANY
, event_ANY
, Handler_CloseWindow
, NULL
);
5324 Event_Claim(event_GAINCARET
, event_ANY
, event_ANY
, Hnd_Caret
, (void *)1);
5325 Event_Claim(event_LOSECARET
, event_ANY
, event_ANY
, Hnd_Caret
, (void *)0);
5326 Event_Claim(event_MENU
, event_ANY
, event_ANY
, Hnd_MenuSel
, NULL
);
5327 Event_Claim(event_CLICK
, window_ICONBAR
, ibar_icon
, Hnd_IbarClick
, NULL
);
5328 Event_Claim(event_CLICK
, event_ANY
, event_ANY
, Hnd_Click
, NULL
);
5329 EventMsg_Claim(message_PALETTECHANGE
, event_ANY
, Hnd_PaletteChange
, NULL
);
5330 EventMsg_Claim(message_MODECHANGE
, event_ANY
, Hnd_ModeChange
, NULL
);
5331 EventMsg_Claim(message_PREQUIT
, event_ANY
, Hnd_PreQuit
, NULL
);
5333 /* Initialise the sound stuff */
5336 #endif /* FULLSCREEN_ONLY */
5338 /* Initialise some Angband stuff */
5341 /* Set up the r_data buffer */
5342 initialise_r_data();
5345 read_alarm_choices();
5347 init_file_paths(unixify_name(resource_path
));
5349 START_HOURGLASS
; /* Paranoia */
5351 /* Hack - override the saved options if -F was on the command line */
5352 start_fullscreen
|= start_full
;
5354 /* hack so that the cursor is yellow if undefined */
5355 if (palette
[CURSOR_COLOUR
] == palette
[0])
5357 angband_color_table
[CURSOR_COLOUR
][1] = (CURSOR_RGB
& 0xff00) >> 8;
5358 angband_color_table
[CURSOR_COLOUR
][2] = (CURSOR_RGB
& 0xff0000) >> 16;
5359 angband_color_table
[CURSOR_COLOUR
][3] = (CURSOR_RGB
& 0xff000000) >> 24;
5362 /* Catch nasty signals */
5365 /* use pref-acn.prf */
5366 ANGBAND_SYS
= "acn";
5368 #ifndef FULLSCREEN_ONLY
5369 if (start_fullscreen
)
5371 #endif /* FULLSCREEN_ONLY */
5372 Event_Claim(event_NULL
, event_ANY
, event_ANY
, Hnd_null
, NULL
);
5373 enter_fullscreen_mode();
5374 #ifndef FULLSCREEN_ONLY
5378 START_HOURGLASS
; /* Paranoia */
5379 Hnd_ModeChange(NULL
, NULL
); /* Caches the various fonts/palettes */
5383 Event_Claim(event_NULL
, event_ANY
, event_ANY
, Hnd_null
, NULL
);
5385 /* Wait for a null poll so that the windows can appear */
5390 while (event_lastevent
.type
!= event_NULL
);
5392 #endif /* FULLSCREEN_ONLY */
5394 /* Initialise Angband */
5395 START_HOURGLASS
; /* Paranoia */
5397 strncpy(savefile
, unixify_name(arg_savefile
), sizeof(savefile
));
5398 savefile
[sizeof(savefile
) - 1] = '\0';
5403 game_in_progress
= 1;
5404 pause_line(PAUSE_LINE_PARAM
);
5409 if (fullscreen_mode
) leave_fullscreen_mode();
5417 debug("to stop the 'unused' warning :)");
5433 | We use this to keep the mouse in the same place on return from full-screen
5436 static wimp_point old_mouse_posn
;
5438 /* Nasty hack to remember how big the main window is when not in fullscreen */
5439 static int main_wid
, main_hgt
;
5442 | Take a copy of the current mode descriptor/number and return either
5443 | a pointer to it (as an int) if it's a new mode, or the mode number.
5444 | NB: A static pointer is used and the descriptor returned is only
5445 | valid until the next call to this function.
5447 | Basically, a replacement for OS_Byte 135 / OS_ScreenMode1, IYSWIM.
5449 static int current_mode(void)
5451 static void *descriptor
= NULL
;
5463 SWI(1, 3, SWI_OS_Byte
, 135, NULL
, NULL
, &mode
);
5469 vals
= (int *)(mode
+ 20);
5470 for (i
= 0; vals
[i
] != -1; i
+= 2)
5473 size
= 24 + 8 * i
; /* Size of data */
5474 descriptor
= malloc(size
);
5477 core("Out of memory!");
5479 memcpy(descriptor
, (void *)mode
, size
);
5481 return (int)descriptor
;
5487 | Select the best mode we can for full screen.
5488 | Returns 12 for (low-res, ie. mode 12) or 27 for high-res,
5489 | or a pointer to a mode descriptor (as an int).
5491 static int select_fullscreen_mode(void)
5495 int flags
, x
, y
, l2bpp
, hz
, term
;
5500 desc
.flags
= 1; /* format 0 */
5502 desc
.y
= 480; /* 640x480 */
5503 desc
.l2bpp
= 2; /* 16 colours */
5504 desc
.hz
= -1; /* best we can get */
5505 desc
.term
= -1; /* don't fuss about modevars */
5507 SWI(1, 1, SWI_OS_CheckModeValid
, &desc
, &mode
);
5508 if (mode
!= (int)&desc
)
5510 SWI(1, 1, SWI_OS_CheckModeValid
, 27, /**/ &mode
);
5513 SWI(1, 1, SWI_OS_CheckModeValid
, 12, /**/ &mode
);
5526 | Change screen mode
5528 static void change_screenmode(int to
)
5530 if (SWI(2, 0, SWI_OS_ScreenMode
, 0, to
))
5539 /* Finished with my woman / cos she couldn't help me with ... */
5540 core("Eeek! mode isn't valid, but it /should/ be...");
5547 | Constrain the mouse pointer to a point - this means that the damn
5548 | hourglass won't move around with the mouse :)
5550 static void constrain_pointer(void)
5554 int ys
= screen_eig
.y
== 1 ? 32 : 64; /* Cope with dbl height glass */
5556 Screen_CacheModeInfo(); /* Make sure we know the screen size */
5557 r
.min
.x
= r
.max
.x
= screen_size
.x
- 32;
5558 r
.min
.y
= r
.max
.y
= screen_size
.y
- ys
;
5560 /* Retrieve and store old (wimp) pointer position */
5561 Wimp_GetPointerInfo(&ptr
);
5562 old_mouse_posn
= ptr
.pos
;
5564 Pointer_RestrictToRect(r
);
5566 /* Turn the pointer off also */
5567 SWI(2, 0, SWI_OS_Byte
, 106, 0);
5570 static void release_pointer(void)
5574 r
.min
.x
= r
.max
.x
= old_mouse_posn
.x
;
5575 r
.min
.y
= r
.max
.y
= old_mouse_posn
.y
;
5577 Pointer_RestrictToRect(r
);
5579 Pointer_Unrestrict();
5581 /* Turn the pointer back on also */
5582 SWI(2, 0, SWI_OS_Byte
, 106, 1);
5587 | Convert a 1bpp bitmap into a 4bpp bitmap (bit flipped)
5589 static int byte_to_word_flipped(int b
)
5635 | try to load the fallback fullscreen font and convert it to 4bpp
5637 static int cache_zapfontHR(void)
5640 unsigned int extent
;
5645 int w
, h
, f
, l
, r1
, r2
;
5652 /* Try to open the file */
5653 sprintf(buffer
, "%s%s", resource_path
, "xtra.FullScreen");
5654 handle
= File_Open(buffer
, (file_access
) 0x4f);
5660 /* Check file's extent */
5661 extent
= File_ReadExtent(handle
);
5662 if (extent
> sizeof(zfh
) + 256 * 16)
5668 /* Load the header */
5669 if (myFile_ReadBytes(handle
, &zfh
, sizeof(zfh
)))
5675 /* Check font size */
5676 if ((zfh
.w
!= 8) || (zfh
.h
> 16))
5682 /* Load the 1bpp data */
5683 if (myFile_ReadBytes(handle
, fullscreen_font
, extent
- sizeof(zfh
)))
5691 l
= zfh
.l
> 255 ? 255 : zfh
.l
;
5695 op
= (int *)(((int)fullscreen_font
) + (l
+ 1) * zfh
.h
* 4);
5696 ip
= (char *)(((int)fullscreen_font
) + (l
+ 1) * zfh
.h
-
5698 while (l
-- >= zfh
.f
)
5700 for (i
= 0; i
< zfh
.h
; i
++)
5702 *--op
= byte_to_word_flipped(*--ip
);
5705 fullscreen_height
= zfh
.h
;
5709 op
= (int *)(((int)fullscreen_font
) + (l
+ 1) * zfh
.h
* 8);
5710 ip
= (char *)(((int)fullscreen_font
) + (l
+ 1) * zfh
.h
-
5712 while (l
-- >= zfh
.f
)
5714 for (i
= -zfh
.h
; i
< zfh
.h
; i
++)
5716 int t
= byte_to_word_flipped(*--ip
);
5721 fullscreen_height
= zfh
.h
* 2;
5724 fullscreen_topline
= TERM_TOPLINE_HR
;
5725 fullscreen_topline
+= ((16 - fullscreen_height
) * 13);
5734 static int cache_fs_fontHR(void)
5736 ZapFont
*src
= SYSTEM_FONT
;
5741 /* Allocate the storage for the font */
5742 fullscreen_font
= f_malloc(256 * 4 * 16);
5743 if (!fullscreen_font
)
5747 op
= (int *)fullscreen_font
;
5749 /* Check to see if the main term's font is suitable (ie. 8x16 or 8x8) */
5750 if ((data
[0].font
->w
== 8) && (data
[0].font
->h
<= 16))
5754 | Hack: if we're forced to use the system font, try to load the
5755 | 'fullscreen' font from lib.xtra. If that fails, then I guess we're
5756 | stuck with the system font.
5759 if (src
== SYSTEM_FONT
)
5760 if (cache_zapfontHR())
5765 ip
= (char *)(src
->bpp_1
);
5767 /* Now, create the font */
5770 int e
= src
->h
* (src
->l
> 256 ? 256 : src
->l
);
5771 op
+= (src
->f
* src
->h
);
5772 for (c
= src
->f
* src
->h
; c
< e
; c
++)
5773 *op
++ = byte_to_word_flipped(*ip
++);
5774 fullscreen_height
= src
->h
;
5778 int e
= src
->h
* (src
->l
> 256 ? 256 : src
->l
);
5779 op
+= (src
->f
* src
->h
) * 2;
5780 for (c
= src
->f
* src
->h
; c
< e
; c
++)
5782 int t
= byte_to_word_flipped(*ip
++);
5786 fullscreen_height
= src
->h
* 2;
5789 fullscreen_topline
= TERM_TOPLINE_HR
;
5790 fullscreen_topline
+= ((16 - fullscreen_height
) * 13);
5799 static int cache_fs_fontLR(void)
5801 ZapFont
*src
= SYSTEM_FONT
;
5806 /* Allocate the storage for the font */
5807 fullscreen_font
= f_malloc(256 * 4 * 8);
5808 if (!fullscreen_font
)
5812 op
= (int *)fullscreen_font
;
5814 /* Check to see if the main term's font is suitable (ie. 8x8) */
5815 if ((data
[0].font
->w
== 8) && (data
[0].font
->h
<= 8))
5818 ip
= (char *)(src
->bpp_1
);
5820 /* Now, create the font */
5821 e
= src
->h
* (src
->l
> 256 ? 256 : src
->l
);
5822 op
+= (src
->f
* src
->h
);
5823 for (c
= src
->f
* src
->h
; c
< e
; c
++)
5824 *op
++ = byte_to_word_flipped(*ip
++);
5826 fullscreen_height
= src
->h
;
5827 fullscreen_topline
= TERM_TOPLINE_LR
;
5828 fullscreen_topline
+= ((8 - fullscreen_height
) * 13);
5835 static void set_keys(int claim
)
5837 static int old_c_state
;
5838 static int old_f_state
[8];
5843 /* Cursors/copy act as function keys */
5844 /* f0-f9, cursors, generate 0x80-0x8f */
5845 /* sh-f0-f9,cursors, generate 0x90-0x9f */
5846 /* ctrl f0-f9,cursors, generate 0xa0-0xaf */
5847 /* sh-c-f0-f9,cursors, generate 0xb0-0xbf */
5848 /* f10-f12 generate 0xca-0xcc */
5849 /* shift f10-f12 generate 0xda-0xdc */
5850 /* ctrl f10-f12 generate 0xea-0xec */
5851 /* ctrlshift f10-f12 generate 0xfa-0xfc */
5853 SWI(3, 2, SWI_OS_Byte
, 4, 2, 0, /**/ NULL
, &old_c_state
);
5855 for (i
= 0; i
< 4; i
++)
5857 SWI(3, 2, SWI_OS_Byte
, 225 + i
, 0x80 + (i
* 0x10), 0, NULL
,
5859 SWI(3, 2, SWI_OS_Byte
, 221 + i
, 0xc0 + (i
* 0x10), 0, NULL
,
5860 old_f_state
+ i
+ 4);
5865 SWI(3, 0, SWI_OS_Byte
, 4, old_c_state
, 0);
5866 for (i
= 0; i
< 4; i
++)
5868 SWI(3, 0, SWI_OS_Byte
, 225 + i
, old_f_state
[i
], 0);
5869 SWI(3, 0, SWI_OS_Byte
, 221 + i
, old_f_state
[i
+ 4], 0);
5880 | Enter the full screen mode.
5882 | Full screen display uses either mode 27 (if supported) and 8x16 fonts
5883 | (or system font 'twiddled' to double height), or mode 12 (if mode 27
5884 | is unavailable) and the system font (or an 8x8 font).
5888 static void enter_fullscreen_mode(void)
5894 /* New in 1.18 - protect against 're-entracy' */
5895 if (fullscreen_font
)
5898 /* Choose the mode we want */
5899 fullscreen_mode
= select_fullscreen_mode();
5901 if (!fullscreen_mode
)
5903 plog("Unable to select a suitable screen mode (27 or 12)");
5907 if (!((fullscreen_mode
== 12) ? cache_fs_fontLR() : cache_fs_fontHR()))
5909 plog("Unable to cache a font for full screen mode");
5913 /* Read the current screen mode */
5914 /* SWI( 1,3, SWI_OS_Byte, 135, NULL, NULL, &old_screenmode ); */
5915 old_screenmode
= current_mode();
5919 /* Change to the chosen screen mode */
5920 change_screenmode(fullscreen_mode
);
5922 /* Restrict the pointer */
5923 constrain_pointer();
5925 /* Remove the cursors */
5926 SWI(0, 0, SWI_OS_RemoveCursors
);
5930 /* Get the base address of screen memory */
5931 SWI(2, 0, SWI_OS_ReadVduVariables
, vduvars
, vduvars
);
5932 fullscreen_base
= (int *)(vduvars
[0]);
5934 /* Fudge the Term interface */
5935 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
5937 term
*t
= &(data
[i
].t
);
5938 t
->wipe_hook
= Term_wipe_acnFS
;
5939 t
->curs_hook
= Term_curs_acnFS
;
5940 t
->text_hook
= Term_text_acnFS
;
5943 /* Grab the palette */
5944 Term_xtra_acn_reactFS(TRUE
);
5946 /* Make sure that the keys work properly */
5949 main_wid
= data
[0].t
.wid
;
5950 main_hgt
= data
[0].t
.hgt
;
5951 term_change_size(&data
[0], 80, 24);
5953 /* refresh the term */
5954 /*Term_activate( &(data[0].t) ); */
5955 redraw_areaFS(0, 0, 80, 24);
5956 if (data
[0].cursor
.visible
)
5957 draw_cursor(data
[0].cursor
.pos
.x
, data
[0].cursor
.pos
.y
);
5959 /* Display a reminder of how to get back... */
5960 /* Hack: disable force_mono */
5963 Term_text_acnFS(0, TIME_LINE
, strlen(fs_quit_key_text
), 8,
5971 static void leave_fullscreen_mode(void)
5975 /* New in 1.18 - protect against 're-entracy' */
5976 if (!fullscreen_font
) return;
5978 /* Restore the screen mode */
5979 Wimp_SetMode(old_screenmode
);
5981 /* Restore the Term interface */
5982 term_change_size(&data
[0], main_wid
, main_hgt
);
5984 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
5986 #ifndef FULLSCREEN_ONLY
5987 term
*t
= &(data
[i
].t
);
5988 t
->wipe_hook
= Term_wipe_acn
;
5989 t
->curs_hook
= Term_curs_acn
;
5990 t
->text_hook
= Term_text_acn
;
5992 mark_ood(&(data
[i
]), 0, 0, data
[i
].t
.wid
, data
[i
].t
.hgt
);
5995 /* Deallocate the font */
5996 f_free(fullscreen_font
);
5997 fullscreen_font
= 0;
5998 fullscreen_mode
= 0;
6002 /* Restore the pointer */
6007 /* Restore the various soft keys */
6010 #ifndef FULLSCREEN_ONLY
6011 /* Refresh the windows - this probably isn't necessary anyway */
6012 if (!minimise_memory
) refresh_windows();
6013 #endif /* FULLSCREEN_ONLY */
6020 static void fs_writechars(int x
, int y
, int n
, const char *chars
, char attr
)
6029 if (attr
!= TERM_DARK
)
6034 fgm
= (unsigned int)zpalette
[(unsigned int) attr
];
6036 scrb
= (int *)(((int)fullscreen_base
) + y
* fullscreen_height
* 320
6037 + x
* 4 + 320 * fullscreen_topline
);
6042 cdat
= (int *)(((int)fullscreen_font
)
6043 + (*chars
++) * (fullscreen_height
<< 2));
6044 for (j
= 0; j
< fullscreen_height
; j
++)
6046 *scr
= *cdat
++ & fgm
;
6053 static void fs_writechar(int x
, int y
, char c
, char attr
)
6062 if (attr
!= TERM_DARK
)
6067 fgm
= (unsigned int)zpalette
[(unsigned int) attr
];
6069 scrb
= (int *)(((int)fullscreen_base
) + y
* fullscreen_height
* 320
6070 + x
* 4 + 320 * fullscreen_topline
);
6071 cdat
= (int *)(((int)fullscreen_font
) + (c
* (fullscreen_height
<< 2)));
6072 for (j
= 0; j
< fullscreen_height
; j
++)
6074 *scrb
= *cdat
++ & fgm
;
6081 static void draw_cursorHR(int x
, int y
)
6083 ColourTrans_SetGCOL(cursor_rgb
, 0, 0);
6085 959 - y
* (fullscreen_height
* 2) - fullscreen_topline
* 2);
6087 GFX_DrawBy(0, -(fullscreen_height
* 2 - 2));
6089 GFX_DrawBy(0, fullscreen_height
* 2 - 2);
6092 static void draw_cursorLR(int x
, int y
)
6094 ColourTrans_SetGCOL(cursor_rgb
, 0, 0);
6096 1023 - y
* (fullscreen_height
* 4) - fullscreen_topline
* 4);
6098 GFX_DrawBy(0, -(fullscreen_height
* 4 - 4));
6100 GFX_DrawBy(0, fullscreen_height
* 4 - 4);
6107 static void draw_cursor(int x
, int y
)
6109 if (fullscreen_mode
== 12)
6110 draw_cursorLR(x
, y
);
6112 draw_cursorHR(x
, y
);
6117 static void redraw_areaFS(int x
, int y
, int w
, int h
)
6120 for (j
= y
; j
< y
+ h
; j
++)
6121 for (i
= x
; i
< x
+ w
; i
++)
6122 fs_writechar(i
, j
, data
[0].t
.old
->c
[j
][i
], data
[0].t
.old
->a
[j
][i
]);
6127 static int wimp_code(int c
)
6129 /* shift/ctrl keypad? */
6130 if (c
>= '0' && c
<= '9')
6132 kbd_modifiers m
= Kbd_GetModifiers(FALSE
);
6150 } /* normal ASCII/ctrl */
6151 if (c
>= 0x80 && c
<= 0xff)
6156 return -1; /* unknown */
6162 static void do_keypress(int code
)
6164 static const char hex
[] = "0123456789ABCDEF";
6166 if (code
== KEYPRESS_QUIT
&& !minimise_memory
)
6168 #ifdef FULLSCREEN_ONLY
6171 leave_fullscreen_mode();
6178 if (Kbd_KeyDown(inkey_CTRL
))
6187 Term_keypress(code
);
6192 Term_keypress(hex
[(code
& 0xf00) >> 8]);
6193 Term_keypress(hex
[(code
& 0x0f0) >> 4]);
6194 Term_keypress(hex
[(code
& 0x00f)]);
6202 static errr
Term_xtra_acn_eventFS(int valid
)
6210 /* Loop if we want validation of the keypress */
6215 /* Check if there are keypresses in the buffer */
6216 SWI(3, 3, SWI_OS_Byte
, 128, 255, 0, NULL
, &bl
, &bh
);
6217 bl
= (bl
& 0xff) | (bh
<< 8);
6221 /* Read a keypress */
6222 SWI(0, 1, SWI_OS_ReadC
, &c
);
6224 /* If valid, process it */
6226 if (w
>= 0) do_keypress(w
);
6228 } while (valid
&& w
== -1);
6240 static errr
Term_xtra_acn_reactFS(int force
)
6245 static int old_gamma
= -1;
6247 if (gamma
!= old_gamma
)
6253 /* Set the screen colours */
6254 for (i
= 0; i
< 16; i
++)
6256 if (COLOUR_CHANGED(i
) || force
)
6259 pow(angband_color_table
[i
][1] / 255.0, 1.0 / ((double) gamma
/ 100)));
6261 pow(angband_color_table
[i
][2] / 255.0, 1.0 / ((double) gamma
/ 100)));
6263 pow(angband_color_table
[i
][3] / 255.0, 1.0 / ((double) gamma
/ 100)));
6271 palette
[i
] = (b
<< 24) | (g
<< 16) | (r
<< 8);
6278 a_palette
[i
][1] = angband_color_table
[i
][1];
6279 a_palette
[i
][2] = angband_color_table
[i
][2];
6280 a_palette
[i
][3] = angband_color_table
[i
][3];
6282 /* Find any higher colour numbers and make them "wrong" */
6283 for (p
= 16; p
< 256; p
++)
6284 if ((zpalette
[p
] & 0xf) == i
)
6285 a_palette
[p
][1] = angband_color_table
[p
][1] + 2;
6290 /* Go through the palette updating any changed values */
6291 for (i
= 16; i
< 256; i
++)
6293 if (COLOUR_CHANGED(i
) || force
)
6296 pow(angband_color_table
[i
][1] / 255.0, 1.0 / ((double) gamma
/ 100)));
6298 pow(angband_color_table
[i
][2] / 255.0, 1.0 / ((double) gamma
/ 100)));
6300 pow(angband_color_table
[i
][3] / 255.0, 1.0 / ((double) gamma
/ 100)));
6301 p
= (b
<< 24) | (g
<< 16) | (r
<< 8);
6303 SWI(1, 1, SWI_ColourTrans_ReturnColourNumber
, palette
[i
], &p
);
6308 a_palette
[i
][1] = angband_color_table
[i
][1];
6309 a_palette
[i
][2] = angband_color_table
[i
][2];
6310 a_palette
[i
][3] = angband_color_table
[i
][3];
6314 cursor_rgb
= palette
[CURSOR_COLOUR
];
6320 static errr
Term_curs_acnFS(int x
, int y
)
6322 if (Term
== &(data
[0].t
))
6324 if (data
[0].cursor
.visible
)
6325 redraw_areaFS(data
[0].cursor
.pos
.x
, data
[0].cursor
.pos
.y
, 1, 1);
6326 data
[0].cursor
.pos
.x
= x
;
6327 data
[0].cursor
.pos
.y
= y
;
6328 if (data
[0].cursor
.visible
)
6334 static errr
Term_xtra_acn_clearFS(void)
6339 if (Term
== &(data
[0].t
))
6341 for (j
= 0; j
< 80; j
++)
6346 for (j
= 0; j
< 24; j
++)
6347 fs_writechars(0, j
, 80, e
, 0);
6357 static errr
Term_wipe_acnFS(int x
, int y
, int n
)
6359 if (Term
== &(data
[0].t
))
6361 fs_writechar(x
++, y
, ' ', 0);
6365 static errr
Term_text_acnFS(int x
, int y
, int n
, byte a
, cptr s
)
6367 if (Term
== &(data
[0].t
))
6368 fs_writechars(x
, y
, n
, s
, (char)a
);
6376 static unsigned int last
;
6382 static int alarm_flash
= 1;
6385 /* Really no need to check the alarm more than once per second. */
6386 if (alarm_type
&& Time_Monotonic() > alarm_lastcheck
+ 100)
6391 l
= Time_Monotonic();
6392 if ((l
- last
) < (alarm_flash
? 25 : 50))
6399 lt
= localtime(&ct
);
6400 l
= strftime(ts
, 80, "%c %Z", lt
);
6402 /* Hack: disable force_mono around printing the time */
6406 /* Hack: Is the alarm supposed to be going off? */
6407 if (alarm_disp
|| alarm_flash
)
6415 switch (alarm_flash
/ 2)
6417 case 4: sprintf(blk
, "%-57s", alarm_cancel_text
);
6419 case 5: sprintf(blk
, "%-57s", fs_quit_key_text
);
6422 c
= alarm_flash
& 1 ? TERM_RED
: TERM_WHITE
;
6423 sprintf(blk
, "%02d:%02d %-51s", alarm_h
, alarm_m
,
6426 fs_writechars(0, TIME_LINE
, 57, blk
, c
);
6427 if (++alarm_flash
> 11)
6434 fs_writechar(79 - l
, TIME_LINE
, ' ', 0);
6435 fs_writechars(80 - l
, TIME_LINE
, l
, ts
, 8);
6446 /*--------------------------------------------------------------------------*/
6447 /* (Simple) Heap management (using OS_Heap) */
6448 /*--------------------------------------------------------------------------*/
6452 static os_error
*Heap_Initialise(heap h
, size_t size
)
6454 return SWI(4, 0, SWI_OS_Heap
, 0, h
, 0, size
);
6457 static void *Heap_Claim(heap h
, size_t size
)
6461 e
= SWI(4, 3, SWI_OS_Heap
, 2, h
, 0, size
, NULL
, NULL
, &fred
);
6462 return e
? NULL
: fred
;
6465 static os_error
*Heap_Release(heap h
, void *block
)
6467 return SWI(3, 0, SWI_OS_Heap
, 3, h
, block
);
6470 static int Heap_ChangeHeapSize(heap h
, int resize_by
)
6473 SWI(4, 4, SWI_OS_Heap
, 5, h
, 0, resize_by
, 0, 0, 0, &by
);
6479 /*--------------------------------------------------------------------------*/
6480 /* Stuff below here is for using Dynamic areas (under RO3.5+) */
6481 /*--------------------------------------------------------------------------*/
6483 static int game_area
= -1; /* The DA the game is using */
6484 static int font_area
= -1; /* The DA the fonts are using */
6486 static void *game_area_base
; /* base address of game area */
6487 static void *font_area_base
; /* base address of font area */
6489 static int font_area_size
; /* size of the fonts' DA */
6490 static int font_heap_size
; /* size of the fonts' heap */
6491 static int game_area_size
; /* size of the game's DA */
6492 static int game_heap_size
; /* size of the game's heap */
6494 #define MAX_F_DA_SIZE (2<<20) /* Max size of font area (2Mb) */
6495 #define MAX_G_DA_SIZE (4<<20) /* Max size of game area (4Mb) */
6496 #define SHRINK_GRAN (4<<10) /* Try to recalaim wastage > this (4Kb) */
6500 | Free dynamic areas when we exit
6502 static void cleanup_memory(void)
6504 if (game_area
!= -1)
6506 SWI(2, 0, SWI_OS_DynamicArea
, 1, game_area
);
6510 if (font_area
!= -1)
6512 SWI(2, 0, SWI_OS_DynamicArea
, 1, font_area
);
6521 | Set up the memory allocation stuff.
6522 | We check to see if DAs are possible and if so initialise two:
6523 | one for the game's use (via the rnalloc() hooks) and one for
6524 | our own use (for fonts, etc).
6526 | Each area is created 16Kb in size, with a max size of 2/4Mb.
6528 | If 'daf' is TRUE, an area is created for the fonts.
6529 | If 'dag' is TRUE, an area is created for the game.
6531 static void init_memory(int daf
, int dag
)
6543 e
= SWI(9, 4, SWI_OS_DynamicArea
, 0, /* Create */
6544 -1, /* Let OS allocate no. */
6545 16 << 10, /* Initial size */
6546 -1, /* Let OS allocate address */
6547 1 << 7, /* Cacheable, bufferable, RW */
6548 MAX_F_DA_SIZE
, /* Max size */
6550 0, /* handler workspace */
6551 VARIANT
" font data", /* Name */
6554 &font_area
, /* area number allocated */
6556 &font_area_base
/* base address of area */
6561 game_area
= font_area
= -1;
6562 game_area_base
= font_area_base
= 0; /* paranoia */
6567 e
= SWI(2, 3, SWI_OS_DynamicArea
, 2, font_area
,
6568 NULL
, NULL
, &font_area_size
);
6571 Error_ReportFatal(e
->errnum
, "%d:%s", e
->errmess
);
6574 e
= Heap_Initialise((heap
) font_area_base
, font_area_size
);
6577 Error_ReportFatal(e
->errnum
, "%d:%s", e
->errmess
);
6579 font_heap_size
= font_area_size
;
6583 /* Make sure DA(s) are removed when we quit */
6584 atexit(cleanup_memory
);
6594 e
= SWI(9, 4, SWI_OS_DynamicArea
, 0, /* Create */
6595 -1, /* Let OS allocate no. */
6596 16 << 10, /* Initial size */
6597 -1, /* Let OS allocate address */
6598 1 << 7, /* Cacheable, bufferable, RW */
6599 MAX_G_DA_SIZE
, /* Max size */
6601 0, /* handler workspace */
6602 VARIANT
" game data", /* Name */
6605 &game_area
, /* area number allocated */
6607 &game_area_base
/* base address of area */
6613 game_area_base
= 0; /* paranoia */
6617 e
= SWI(2, 3, SWI_OS_DynamicArea
, 2, game_area
,
6618 NULL
, NULL
, &game_area_size
);
6621 Error_ReportFatal(e
->errnum
, "%d:%s", e
->errmess
);
6624 e
= Heap_Initialise((heap
) game_area_base
, game_area_size
);
6627 Error_ReportFatal(e
->errnum
, "%d:%s", e
->errmess
);
6629 game_heap_size
= game_area_size
;
6634 static int grow_dynamicarea(int area
, int by
)
6637 e
= SWI(2, 2, SWI_OS_ChangeDynamicArea
, area
, by
, /**/ NULL
, &by
);
6638 /* Can't check errors since a 'failed' shrink returns one... */
6644 | Try to shrink the font-cache heap and area as much as possible.
6646 static void f_shrink_heap(void)
6649 /* Shrink the heap as far as possible */
6651 Heap_ChangeHeapSize((heap
) font_area_base
, -MAX_F_DA_SIZE
);
6652 /* Shrink the dynamic area if necessary */
6653 s
= font_area_size
- font_heap_size
;
6654 if (s
>= SHRINK_GRAN
)
6655 font_area_size
-= grow_dynamicarea(font_area
, -s
);
6659 | Allocate a block of memory in the font heap
6661 static void *f_malloc(size_t size
)
6665 if (font_area
== -1)
6667 return malloc(size
);
6669 c
= Heap_Claim((heap
) font_area_base
, size
);
6673 /* The Claim failed. Try to grow the area by the size of the block */
6674 s
= grow_dynamicarea(font_area
, size
+ 64); /* 64 is overkill */
6679 font_area_size
+= s
;
6680 s
= font_area_size
- font_heap_size
;
6681 font_heap_size
+= Heap_ChangeHeapSize((heap
) font_area_base
, s
);
6682 c
= Heap_Claim((heap
) font_area_base
, size
);
6693 | Free a block of memory in the font heap
6695 static void f_free(void *blk
)
6698 if (font_area
== -1)
6703 e
= Heap_Release((heap
) font_area_base
, blk
);
6705 Msgs_ReportFatal(e
->errnum
, "err.swi", __LINE__
, e
->errmess
);
6714 | Allocate a block of memory in the game heap
6721 if (game_area
== -1)
6723 return malloc((size_t) size
);
6725 c
= Heap_Claim((heap
) game_area_base
, (size_t) size
+ 4);
6728 /* The Claim failed. Try to grow the area by the size of the block */
6729 s
= grow_dynamicarea(game_area
, (size_t) size
+ 64); /* 64 is overkill */
6734 game_area_size
+= s
;
6735 s
= game_area_size
- game_heap_size
;
6736 game_heap_size
+= Heap_ChangeHeapSize((heap
) game_area_base
, s
);
6737 c
= Heap_Claim((heap
) game_area_base
, (size_t) size
+ 4);
6742 strcpy((char *)c
, "MUSH");
6743 c
= (void *)(((int)c
) + 4);
6747 fprintf(stderr
, "ralloc(%ld) == %p\n", (long)size
, c
);
6754 | Free a block of memory in the game heap
6756 | The 'len' is to be compatible with z-virt.c (we don't need/use it)
6764 if (game_area
== -1)
6771 fprintf(stderr
, "rnfree(%p)\n", blk
);
6773 if (strncmp(((char *)blk
) - 4, "MUSH", 4))
6774 core("game heap corrupt / bad attempt to free memory");
6776 blk
= (void *)(((int)blk
) - 4);
6778 e
= Heap_Release((heap
) game_area_base
, blk
);
6780 Msgs_ReportFatal(e
->errnum
, "err.swi", __LINE__
, e
->errmess
);
6782 /* Shrink the heap as far as possible */
6784 Heap_ChangeHeapSize((heap
) game_area_base
, -MAX_G_DA_SIZE
);
6786 /* Shrink the dynamic area if necessary */
6787 s
= game_area_size
- game_heap_size
;
6788 if (s
>= SHRINK_GRAN
)
6789 game_area_size
-= grow_dynamicarea(game_area
, -s
);
6799 /*--------------------------------------------------------------------------*/
6802 | New to 1.04: Sound support :)
6804 | We use the PlayIt module (for convenience).
6806 | The Lib/xtra/sound/sound.cfg file is used to map sample names onto
6809 | Since textual names are used in the .cfg file, we need to have a lookup
6810 | table to translate them into numbers. At present we use the
6811 | angband_sound_name array defined in variable.c
6813 | Since there can be multiple sounds for each event we need to use a
6814 | list to store them.
6817 /* NB: This will be clipped to 10 under RISC OS 2 */
6818 #define MAX_SAMPNAME_LEN 64
6826 typedef struct samp_node
6828 char sample_name
[MAX_SAMPNAME_LEN
+ 1]; /* Sample name */
6829 struct samp_node
*next
; /* -> next node */
6833 typedef struct samp_info
6835 int samples
; /* # samples for this event */
6836 SampNode
*samplist
; /* list of sample names */
6842 | Just need an array of SampInfos
6844 static SampInfo sample
[SOUND_MAX
];
6847 | This flag will only be set non-zero if the SampInfo array is
6850 static int sound_initd
= 0;
6853 static void read_sound_config(void)
6858 int max_sampname_len
= truncate_names()? 10 : MAX_SAMPNAME_LEN
;
6861 if (show_sound_alloc
)
6863 sprintf(buffer
, "%s%s", resource_path
, "sndmap/out");
6864 dbo
= fopen(buffer
, "w");
6867 core("can't create sndmap/out debugging file");
6873 /* Initialise the sample array */
6874 for (i
= 0; i
< SOUND_MAX
; i
++)
6876 sample
[i
].samples
= 0;
6877 sample
[i
].samplist
= NULL
;
6883 /* Deallocate the sample lists */
6884 for (i
= 0; i
< SOUND_MAX
; i
++)
6886 SampNode
*si
= sample
[i
].samplist
;
6887 sample
[i
].samples
= 0;
6888 sample
[i
].samplist
= NULL
;
6891 SampNode
*ns
= si
->next
;
6899 /* Open the config file */
6900 sprintf(buffer
, "%sSound:%s", RISCOS_VARIANT
, "sound/cfg");
6901 f
= fopen(buffer
, "r");
6903 /* No cfg file => no sounds */
6906 if (show_sound_alloc
)
6908 fprintf(dbo
, "** Can't open cfg file '%s'\n", buffer
);
6914 /* Parse the file */
6915 while (fgets(buffer
, sizeof(buffer
), f
))
6920 /* Skip comments and lines that begin with whitespace */
6921 if (*buffer
== '#' || isspace((unsigned char)*buffer
))
6926 /* Hack: ignore any line beginning '[' (section marker) */
6932 /* Place a NULL after the event name and find the first sample name */
6933 sample_name
= buffer
;
6934 while (*sample_name
&& !isspace((unsigned char)*sample_name
))
6938 if (*sample_name
== 0)
6941 } /* just ignore it */
6943 /* Terminate the sample name */
6946 /* Look up the event name to get the event number */
6947 for (event_number
= SOUND_MAX
- 1; event_number
>= 0; event_number
--)
6948 if (!strcmp(buffer
, angband_sound_name
[event_number
]))
6951 /* No match -> just ignore the line */
6952 if (event_number
< 0)
6954 if (show_sound_alloc
)
6955 fprintf(dbo
, "* Ignoring unknown event '%s'\n", buffer
);
6960 while (*sample_name
&& *sample_name
!= '=')
6964 if (*sample_name
== 0)
6967 } /* just ignore it */
6974 | Now we find all the sample names and add them to the
6975 | appropriate list in the sample mapping array
6978 while (*sample_name
)
6983 /* Find the start of the next word */
6984 while (isspace((unsigned char)*sample_name
) && *sample_name
)
6993 /* Find the end of the sample name */
6994 s
= sample_name
; /* start of the name */
6995 while (!isspace((unsigned char)*sample_name
) && *sample_name
)
6998 /* Hack: shorten sample names that are too long */
6999 if ((sample_name
- s
) > max_sampname_len
)
7000 s
[max_sampname_len
] = ' ';
7002 /* Allocate a node in the sample list for the event */
7003 if ((sn
= malloc(sizeof(SampNode
))) == NULL
)
7004 core("Out of memory (scanning sound.cfg)");
7006 /* Link the node to the list */
7007 sn
->next
= sample
[event_number
].samplist
;
7008 sample
[event_number
].samplist
= sn
;
7010 /* Imcrement the sample count for that event */
7011 sample
[event_number
].samples
++;
7014 | Copy the sample name into the node, converting it into
7015 | RISC OS style as we go.
7017 for (i
= 0; !isspace((unsigned char)s
[i
]) && s
[i
]; i
++)
7020 sn
->sample_name
[i
] = '/';
7021 else if (s
[i
] == '/')
7022 sn
->sample_name
[i
] = '.';
7024 sn
->sample_name
[i
] = s
[i
];
7027 | The sample name '*' is special and means "no new sound"
7028 | so don't store a filename for these mappings.
7030 if (i
== 1 && sn
->sample_name
[0] == '*')
7034 sn
->sample_name
[i
] = 0;
7038 /* Close the file */
7041 if (show_sound_alloc
)
7046 for (i
= 0; i
< SOUND_MAX
; i
++)
7048 fprintf(dbo
, "\n\nEvent '%s'", angband_sound_name
[i
]);
7049 fprintf(dbo
, " (%d sounds)\n", sample
[i
].samples
);
7050 for (l
= sample
[i
].samplist
; l
; l
= l
->next
)
7051 fprintf(dbo
, "\t%s\n", l
->sample_name
);
7061 | Try to make sure that PlayIt is loaded.
7062 | This requires AngSound rel. 4
7064 static void check_playit(void)
7066 if (SWI(2, 0, SWI_OS_Module
, 18, "PlayIt"))
7069 SWI(2, 1, SWI_OS_File
, 17, "Angsound:LoadPlayIt", &t
);
7071 SWI(1, 0, SWI_OS_CLI
,
7072 "RMEnsure PlayIt 0.00 Run AngSound:LoadPlayIt");
7078 static void initialise_sound(void)
7080 /* Load the configuration file */
7082 read_sound_config();
7085 /* Set the sound hook */
7086 sound_hook
= play_sound
;
7093 static void play_sample(char *leafname
)
7097 strcpy(buffer
, "%playit_stop");
7099 if (!SWI(1, 0, SWI_OS_CLI
, buffer
))
7101 SWI(1, 0, SWI_PlayIt_Volume
, sound_volume
);
7102 sprintf(buffer
, "%%playit_play %sSound:%s", RISCOS_VARIANT
, leafname
);
7103 SWI(1, 0, SWI_OS_CLI
, buffer
);
7111 static void play_sound(int event
)
7114 if (!sound_initd
|| !enable_sound
)
7118 if (event
< 0 || event
>= SOUND_MAX
)
7121 /* msg_format("Sound '%s'",angband_sound_name[event]); */
7123 /* Choose a sample */
7124 if (sample
[event
].samples
)
7126 int s
= rand() % sample
[event
].samples
;
7127 SampNode
*sn
= sample
[event
].samplist
;
7133 plog("Adny botched the sound config - please send him a copy of your sound/cfg file.");
7136 if (*(sn
->sample_name
))
7137 play_sample(sn
->sample_name
);
7144 /*--------------------------------------------------------------------------*/
7147 | This stuff is for the Term_user hook
7149 #ifdef ZANGBAND_TERM_PACKAGE
7150 #define PUT_FSTR put_fstr
7151 #define COL(colour) CLR_##colour
7153 #define PUT_FSTR display_line
7154 #define COL(colour) TERM_##colour
7156 static void display_line(int x
, int y
, int c
, const char *fmt
, ...)
7162 vstrnfmt(buffer
, sizeof(buffer
), fmt
, ap
);
7163 Term_putstr(x
, y
, -1, c
, buffer
);
7171 | Let the user change the alarm message
7173 static void do_alarm_message_input(int y
)
7176 int inspos
= strlen(alarm_message
);
7177 char old_message
[52];
7179 strcpy(old_message
, alarm_message
);
7183 PUT_FSTR(26, y
, COL(YELLOW
), "%-51s", alarm_message
);
7184 Term_gotoxy(26 + inspos
, y
);
7192 case 128: case 8: /* delete */
7195 alarm_message
[--inspos
] = 0;
7198 case 27: /* escape */
7199 strcpy(alarm_message
, old_message
);
7203 if (k
> 31 && k
< 127 && inspos
< 50)
7205 alarm_message
[inspos
++] = k
;
7206 alarm_message
[inspos
] = 0;
7212 PUT_FSTR(26, y
, COL(WHITE
), "%-51s", alarm_message
);
7216 #define tum_col(X) ((X) ? COL(L_BLUE) : COL(WHITE) )
7217 #define tum_onoff(X) ((X) ? "On " : "Off")
7219 static errr
Term_user_acn(int n
)
7224 int redraw_mung
= 0;
7227 /* Will be true if the alarm choices need to be (re)saved */
7228 int alarm_modified
= 0;
7231 | Hack: let the desktop front end know that
7232 | the user menu is active...
7234 user_menu_active
= TRUE
;
7238 | Hack: alarm type 1 /looks/ the same as type 3 but doesn't get
7239 | cancelled as a type 3 would. This allows alarms to go off and
7240 | be cancelled without affecting the alarm type whilst it's being
7243 if (alarm_type
== 3)
7251 Term_activate(&(data
[0].t
));
7253 Term_get_cursor(&cursor_state
);
7254 Term_set_cursor(TRUE
);
7260 PUT_FSTR(2, 1, COL(YELLOW
), "%s %s", VARIANT
, VERSION
);
7261 PUT_FSTR(2, 2, COL(SLATE
), "Front-end %s", PORTVERSION
);
7262 PUT_FSTR(2, 4, COL(WHITE
), "Use cursor up/down to select an option then cursor left/right to alter it.");
7263 PUT_FSTR(2, 5, COL(WHITE
), "Hit 'S' to save these settings (alarm settings are saved automatically).");
7264 PUT_FSTR(2, 6, COL(WHITE
), "Hit ESC to return to the game.");
7266 for (k
= 0; k
< 32; k
++) Term_putch(31 + k
+ (k
/ 2), 8, k
/ 2, '#');
7270 PUT_FSTR(2, 8, tum_col(optn
== 0),
7271 " Gamma correction : %i.%02i", gamma
/ 100, gamma
% 100);
7272 PUT_FSTR(2, 9, tum_col(optn
== 1),
7273 " Force monochrome : %s", tum_onoff(force_mono
));
7274 PUT_FSTR(2, 10, tum_col(optn
== 2),
7275 " Sound effects : %s", tum_onoff(enable_sound
));
7276 PUT_FSTR(2, 11, tum_col(optn
== 3),
7277 " Sound effect volume : ");
7279 sound_volume
> 127 ? COL(RED
) : tum_col(optn
== 3),
7280 "%-3d", sound_volume
);
7281 PUT_FSTR(30, 11, tum_col(optn
== 3), "(127 = full volume)");
7282 PUT_FSTR(2, 12, tum_col(optn
== 4),
7283 " Start fullscreen : %s",
7284 tum_onoff(start_fullscreen
));
7285 PUT_FSTR(30, 12, tum_col(optn
== 4),
7286 "(also selects fullscreen/desktop now)");
7287 PUT_FSTR(2, 13, tum_col(optn
== 5),
7288 " Use hourglass : %s", tum_onoff(use_glass
));
7289 PUT_FSTR(2, 14, tum_col(optn
== 6),
7290 "'Hard' input flushing : %s", tum_onoff(hack_flush
));
7292 PUT_FSTR(2, 16, tum_col(optn
== 7),
7293 " Alarm type : %-20s",
7294 alarm_types
[alarm_type
]);
7295 PUT_FSTR(2, 17, COL(WHITE
),
7297 PUT_FSTR(26, 17, tum_col(optn
== 8), "%02d", alarm_h
);
7298 PUT_FSTR(28, 17, COL(WHITE
), ":");
7299 PUT_FSTR(29, 17, tum_col(optn
== 9), "%02d", alarm_m
);
7300 PUT_FSTR(2, 18, tum_col(optn
== 10),
7301 " Message : %-51s", alarm_message
);
7302 PUT_FSTR(2, 19, tum_col(optn
== 11),
7303 " Beep : %s", tum_onoff(alarm_beep
));
7305 #ifdef FE_DEBUG_INFO
7306 PUT_FSTR(2, 23, tum_col(optn
== 23), "Show debug info");
7312 case 12: Term_gotoxy(26, 23);
7314 case 11: Term_gotoxy(26, 19);
7316 case 10: Term_gotoxy(26, 18);
7318 case 9: Term_gotoxy(29, 17);
7320 case 8: Term_gotoxy(26, 17);
7322 case 7: Term_gotoxy(26, 16);
7324 default: Term_gotoxy(26, optn
+ 8);
7328 adj
= (k
== '4' || k
== 'h') ? -1 : (k
== '6' || k
== 'l') ? 1 : 0;
7332 case 18: /* Hack: force the screen to update */
7338 PUT_FSTR(2, 23, COL(YELLOW
), "Options saved. ");
7340 Term_xtra(TERM_XTRA_DELAY
, 750);
7341 Term_erase(2, 23, 60);
7350 if (++optn
> max_opt
)
7355 case 13: case 32: case 't': /* Allow return, space and t to toggle some options */
7361 case 0: /* Gamma correction */
7371 Term_xtra(TERM_XTRA_REACT
, 0);
7372 #ifndef FULLSCREEN_ONLY
7373 set_gamma_window_state();
7374 #endif /* FULLSCREEN_ONLY */
7378 case 1: /* Force monochrome */
7379 force_mono
= !force_mono
;
7380 if (fullscreen_font
)
7381 redraw_areaFS(0, 0, 80, 24);
7383 Term_xtra(TERM_XTRA_REACT
, 0);
7387 case 2: /* Sound enable / disable */
7388 enable_sound
= !enable_sound
;
7389 #ifndef FULLSCREEN_ONLY
7390 set_sound_window_state();
7391 #endif /* FULLSCREEN_ONLY */
7397 case 3: /* Sound volume */
7398 sound_volume
+= adj
;
7399 if (sound_volume
< SOUND_VOL_MIN
)
7400 sound_volume
= SOUND_VOL_MIN
;
7401 if (sound_volume
> SOUND_VOL_MAX
)
7402 sound_volume
= SOUND_VOL_MAX
;
7403 #ifndef FULLSCREEN_ONLY
7404 set_sound_window_state();
7405 #endif /* FULLSCREEN_ONLY */
7407 case 4: /* Start fullscreen */
7408 start_fullscreen
= !start_fullscreen
;
7409 if (start_fullscreen
)
7410 enter_fullscreen_mode();
7411 else if (!minimise_memory
)
7412 leave_fullscreen_mode();
7414 case 5: /* Start fullscreen */
7415 use_glass
= !use_glass
;
7425 case 6: /* hack flush */
7426 hack_flush
= !hack_flush
;
7428 case 7: /* Alarm on/off */
7442 if (!alarm_type
&& alarm_disp
)
7445 } /* XXXXX Cancel an already active alarm? */
7447 case 8: /* Alarm hours */
7466 case 9: /* Alarm minutes */
7487 do_alarm_message_input(18);
7491 alarm_beep
= !alarm_beep
;
7504 while (redraw_mung
);
7506 /* Rehack the alarm type: */
7507 if (alarm_type
== 1)
7514 write_alarm_choices();
7517 Term_set_cursor(cursor_state
);
7519 /* Restore the screen */
7523 | Hack: tell the desktop front end that we're done.
7525 user_menu_active
= FALSE
;
7533 /*--------------------------------------------------------------------------*/
7535 #ifdef USE_FILECACHE
7538 | 'Random' File-cacheing for *band.
7540 | Rewritten since as of Zang 225 the mechanism for handling
7541 | these files has changed dramatically and the old system
7542 | is no longer viable.
7544 | These new functions basically provide an alternative to the
7545 | normal my_fopen() (or fopen()) and my_fgets() functions.
7547 | To use the file caching it is therefore necessary to alter
7548 | files.c to call cached_fopen(), cached_fclose() and cached_fgets()
7549 | rather than the normal functions.
7551 | Note that these funtions will only work for files that are intended
7552 | to be read as a series of \n terminated lines of ASCII text using my_fgets().
7557 | Hack: use the game's dynamic area if possible:
7559 #define fc_malloc(X) (g_malloc(X))
7560 #define fc_free(X) (g_free(X,0))
7562 #ifndef ABBR_FILECACHE
7564 | Make these to do nothing. They'll never
7565 | be called anyway. Having them present makes
7566 | for neater code later on (ie. we use a variable
7567 | rather than the pre-processor to decide whether
7568 | to do compression).
7570 static int compress_string(char *os
, char *s
)
7572 core("main-acn internal logic error 001");
7575 static int decompress_string(char *d
, char *s
, int max_len
)
7577 core("main-acn internal logic error 002");
7580 static int compressed_length(char *s
)
7582 core("main-acn internal logic error 003");
7589 | When caching files we try to use some abbreviations.
7590 | We use both whole words and pairs of letters.
7591 | NB: For this to work, the file must contain only
7594 static char *abbrv_w
[] =
7596 /* These words all begin with a space */
7597 " of ", " the ", " you ", " to ", " a ", " says", " is ", " that ", " and ",
7598 " your ", " are ", " it ", " be ", " for ", " me", " will ", " in ",
7599 " not ", " this ", " have ", " can ", " on ", " my ", " with ", " say ",
7600 " all", " by ", " get ", " but ", " just ", " die", " as ", " time ",
7603 /* These words do not */
7604 "I ", "The ", "You ", "They ", "It ", "don", 0
7607 /* Number of words */
7608 #define FC_ABBRV_NUMWORDS 41
7610 /* Number of them that don't start with a space */
7611 #define FC_ABBRV_NONSPC 6
7614 | NB: No letter pair may start with \0.
7616 static char abbrv_lp
[] =
7617 "e ttht s heiner aoure'\0, anonf sd y r ongofator.\0"
7618 "n arllstha wes m ieaisen bl yndtoo yometele d f hve"
7619 "ayuralitneelN: chig ilroassaseliti lraa otedbede 'ri" "..u nntno!'ee\0\0";
7623 | Compress the given string using the abbreviation tables above.
7624 | Returns compressed length *including* terminator (it may
7625 | be part of an abbreviation, you see...)
7626 | Note that we can compress the string in-place, ie. 'os' may be
7629 static int compress_string(char *os
, char *s
)
7642 lw
= FC_ABBRV_NUMWORDS
- FC_ABBRV_NONSPC
;
7646 fw
= FC_ABBRV_NUMWORDS
- FC_ABBRV_NONSPC
;
7647 lw
= FC_ABBRV_NUMWORDS
;
7649 for (i
= fw
; i
< lw
; i
++)
7651 d
= abbrv_w
[i
]; /* Word to check against */
7652 for (f
= s
; *f
&& *f
== *d
; f
++, d
++)
7654 if (*d
== 0) /* Match? */
7656 s
= *f
? f
: f
- 1; /* Update string pointer */
7657 *o
++ = 128 + i
; /* store code */
7658 break; /* Quit looking for words */
7662 /* Do we need to check the letter pairs? */
7665 for (i
= 0; abbrv_lp
[i
]; i
+= 2)
7667 if (s
[0] == abbrv_lp
[i
] && s
[1] == abbrv_lp
[i
+ 1])
7669 *o
++ = 128 + FC_ABBRV_NUMWORDS
+ i
/ 2;
7670 /* NB: If the next character is the terminator then we're done. */
7675 s
+= 2; /* Quit looking for letters */
7679 /* NB: This next check is only safe because no letter pair starts with a NULL */
7685 /* Don't forget that terminator! */
7692 | As compress_string (above), but stores nothing and
7693 | only returns the length of the compressed string.
7695 static int compressed_length(char *s
)
7707 lw
= FC_ABBRV_NUMWORDS
- FC_ABBRV_NONSPC
;
7711 fw
= FC_ABBRV_NUMWORDS
- FC_ABBRV_NONSPC
;
7712 lw
= FC_ABBRV_NUMWORDS
;
7714 for (i
= fw
; i
< lw
; i
++)
7717 for (f
= s
; *f
&& *f
== *d
; f
++, d
++)
7719 if (*d
== 0) /* Match? */
7721 s
= *f
? f
: f
- 1; /* Update string pointer */
7722 l
++; /* increment output length */
7723 break; /* Quit looking for words */
7727 /* Do we need to check the letter pairs? */
7730 for (i
= 0; abbrv_lp
[i
]; i
+= 2)
7732 if (s
[0] == abbrv_lp
[i
] && s
[1] == abbrv_lp
[i
+ 1])
7734 l
++; /* increment output length */
7735 /* NB: If the next character is the terminator then we're done. */
7740 s
+= 2; /* Quit looking for letters */
7744 /* NB: This next check is only safe because no letter pair starts with a NULL */
7752 /* Don't forget that terminator! */
7759 | Decompress the given string 's' into the buffer at 'd'.
7760 | At most, max_len characters (incl. \0 terminator) will be
7762 | Returns the length of 's'.
7764 static int decompress_string(char *d
, char *s
, int max_len
)
7770 int nc
= *s
++; /* Get next character */
7772 if (nc
< 128) /* Is it a plain character? */
7774 if (0 == (*d
++ = nc
))
7780 else /* Abbreviation to expand. */
7782 if (nc
>= FC_ABBRV_NUMWORDS
+ 128) /* Letter pair? */
7784 *d
++ = abbrv_lp
[(nc
- (FC_ABBRV_NUMWORDS
+ 128)) * 2];
7786 (*d
++ = abbrv_lp
[(nc
- (FC_ABBRV_NUMWORDS
+ 128)) * 2 + 1]))
7790 else /* It's a word */
7792 char *ws
= abbrv_w
[nc
- 128];
7793 while (*ws
&& max_len
> 1)
7802 /* Skip over the rest of the abbreviated string if we ran out of space */
7803 if (max_len
<= 1) /* Out of space? */
7806 *d
= 0; /* Terminate */
7809 nc
= *s
++; /* Next char */
7810 if (nc
>= 128 + FC_ABBRV_NUMWORDS
) /* Ignore words */
7811 nc
= abbrv_lp
[(nc
- (FC_ABBRV_NUMWORDS
+ 128) * 2) + 1]; /* Only check 2nd letter of pair */
7815 return s
- os
; /* Length of abbreviated string */
7818 #endif /* ABBR_FILECACHE */
7821 /* Each entry in the cache looks like this: */
7824 char *name
; /* canonical pathname of file */
7825 char *text
; /* text (be it compressed or not) */
7826 char *eof
; /* byte beyond the last byte of text */
7827 int used
; /* access counter when the file was last used */
7828 int compressed
; /* compression method, (ie. 0 for none or 1 for abbreviations) */
7833 | The handles we chuck around are pointers to one of these structs.
7834 | Note that since we actually return (and take) |FILE*|s we just
7835 | compare the value of a |FILE*| with the limits of the array of
7836 | |CachedFileHandle|s to decide whether its 'ours' or a genuine
7837 | (ie. stdio) file handle. This /is/ pretty lame, I know...
7841 char *ptr
; /* sequential file pointer, as it were */
7842 FileCacheEntry
*fce
; /* ->the file-cache entry data */
7846 #define MAX_OPEN_CACHED_FILES 16 /* We allow up to 16 of these files open at once */
7847 #define MAX_CACHE_ENTRIES 64 /* We allow up to 64 cache entries */
7849 static FileCacheEntry
*file_cache
; /* to be used as file_cache[MAX_CACHE_ENTRIES] */
7850 static CachedFileHandle
*cached_file_handle
; /* to be used as cached_file_handle[MAX_OPEN_CACHED_FILES] */
7851 static int file_cache_initd
= 0; /* Is the cache initialised? */
7852 static int file_cache_size
= 0; /* Total size of the cached files */
7853 static int fc_access_counter
= 1; /* incremented on each cache access */
7855 | Pre-calculate max. possible value of a FILE* (ie. address in memory)
7856 | that could be a valid |CachedFileHandle*|.
7858 static FILE *max_cfh_addr
; /* == (FILE*) (&(cached_file_handle[MAX_OPEN_CACHED_FILES-1])) */
7861 | Initialise the file cache
7863 static void init_file_cache(void)
7867 /* Allocate storage */
7868 file_cache
= fc_malloc(MAX_CACHE_ENTRIES
* sizeof(FileCacheEntry
));
7869 cached_file_handle
=
7870 fc_malloc(MAX_OPEN_CACHED_FILES
* sizeof(CachedFileHandle
));
7872 if (!file_cache
|| !cached_file_handle
)
7874 /* Disable file-caching */
7877 fc_free(file_cache
);
7879 if (cached_file_handle
)
7881 fc_free(cached_file_handle
);
7887 /* Initialise the cache */
7888 for (i
= 0; i
< MAX_CACHE_ENTRIES
; i
++)
7889 file_cache
[i
].name
= NULL
;
7890 for (i
= 0; i
< MAX_OPEN_CACHED_FILES
; i
++)
7891 cached_file_handle
[i
].fce
= NULL
;
7892 fc_access_counter
= 1;
7893 file_cache_size
= 0;
7895 (FILE *)(&(cached_file_handle
[MAX_OPEN_CACHED_FILES
- 1]));
7897 file_cache_initd
= 1;
7903 | Cache the specified file, returning either the cache entry
7904 | that it has been cached at, or NULL for failure.
7906 | Note that for the abbreviated file cache a temporary file
7907 | is used to allow the compression to be applied just once.
7908 | (otherwise it has to be done twice - once to determine the
7909 | eventual compressed size and once to actually store and compress
7912 static FileCacheEntry
*cache_file(char *name
)
7919 FILE *tf
= NULL
; /* Used if abbr_filecache and abbr_tmpfile are set */
7920 char cfn
[1024]; /* Used if abbr_filecache and abbr_tmpfile are set */
7922 /* Find the first free slot in the cache */
7923 for (i
= 0; i
< MAX_CACHE_ENTRIES
; i
++)
7924 if (!file_cache
[i
].name
)
7927 /* No more entries? */
7928 if (i
>= MAX_CACHE_ENTRIES
)
7933 /* Set up the info on the file */
7934 if ((file_cache
[i
].name
= string_make(name
)) == NULL
)
7940 fp
= my_fopen(name
, "r");
7943 fc_free(file_cache
[i
].name
);
7944 file_cache
[i
].name
= 0;
7948 /* Open/create tempfile if need be: */
7949 if (abbr_filecache
&& abbr_tmpfile
)
7951 /* Hack: Form the pathname of the cached compressed file (in canonical form) */
7952 sprintf(cfn
, "%s%s", scrap_path
,
7953 riscosify_name(name
+ strlen(resource_path
)));
7954 /* Ensure that that particular directory exists... */
7956 /* Check whether cache file is out of date */
7957 if (file_is_newer(riscosify_name(name
), cfn
))
7959 tf
= fopen(cfn
, "wb");
7964 tf
= fopen(cfn
, "rb");
7967 size
= File_Size(cfn
);
7972 /* If we don't have the cached file (but want it), compress the source text to it */
7978 while (!my_fgets(fp
, buffer
, sizeof(buffer
)))
7980 if (smart_filecache
&& (!*buffer
|| *buffer
== '#'))
7982 k
= compress_string(buffer
, buffer
);
7983 if (fwrite(buffer
, 1, k
, tf
) != k
)
7987 core("error writing tempfile");
7992 tf
= fopen(cfn
, "rb");
7997 /* Count the number of bytes */
7998 while (!my_fgets(fp
, buffer
, sizeof(buffer
)))
8000 if (smart_filecache
&& (!*buffer
|| *buffer
== '#'))
8003 size
+= compressed_length(buffer
);
8005 size
+= strlen(buffer
) + 1;
8009 /* Close the (source) file */
8012 /* Allocate enough storage for the text */
8013 file_cache
[i
].text
= fc_malloc(size
+ 1L);
8014 if (!file_cache
[i
].text
)
8016 fc_free(file_cache
[i
].name
);
8017 file_cache
[i
].name
= 0;
8025 /* Do we have a tempfile to load? */
8028 if (fread(file_cache
[i
].text
, 1, size
, tf
) != size
)
8029 core("error reading tempfile");
8034 /* Re-open the file... */
8035 fp
= my_fopen(name
, "r");
8038 fc_free(file_cache
[i
].name
);
8039 fc_free(file_cache
[i
].text
);
8040 file_cache
[i
].name
= 0;
8044 /* And read it into the buffer... */
8045 d
= file_cache
[i
].text
;
8046 while (!my_fgets(fp
, buffer
, sizeof(buffer
)))
8048 if (smart_filecache
&& (!*buffer
|| *buffer
== '#'))
8051 d
+= compress_string(d
, buffer
);
8055 d
+= strlen(buffer
) + 1;
8059 if ((d
- file_cache
[i
].text
) != size
)
8061 debug("Calculated size is %d, pointer offset is %d", size
,
8062 (d
- file_cache
[i
].text
));
8063 core("Cached file is larger than calculated!");
8066 /* Close the file */
8070 /* Set up the 'last accessed' value, etc. */
8071 file_cache
[i
].used
= fc_access_counter
++;
8072 file_cache
[i
].eof
= file_cache
[i
].text
+ size
;
8073 file_cache
[i
].compressed
= abbr_filecache
;
8074 file_cache_size
+= size
;
8076 /* Return success */
8077 return &(file_cache
[i
]);
8082 | Discard a file from the cache
8084 static void discard_cached_file(int i
)
8086 if (!file_cache
[i
].name
)
8089 } /* invalid request */
8090 fc_free(file_cache
[i
].text
);
8091 fc_free(file_cache
[i
].name
);
8092 file_cache_size
-= (file_cache
[i
].eof
) - (file_cache
[i
].text
);
8093 file_cache
[i
].name
= 0;
8098 | Attempt to flush as much of the cache as required
8099 | to bring it within the size limit.
8100 | If protect != 0 then that entry in the cache won't be flushed.
8102 static void flush_file_cache(FileCacheEntry
* protect
)
8105 int oldest_u
, oldest_e
;
8106 FileCacheEntry
*fce
;
8107 int needed
= (4 << 10); /* Hack: try to free at least 4K */
8109 done
= (file_cache_size
+ needed
) <= max_file_cache_size
;
8113 oldest_u
= fc_access_counter
;
8117 /* Find oldest entry that isn't in use */
8118 for (i
= 0; i
< MAX_CACHE_ENTRIES
; fce
++, i
++)
8124 if (fce
->name
) /* Is this cache slot full? */
8126 for (j
= 0; j
< MAX_OPEN_CACHED_FILES
; j
++)
8127 if (cached_file_handle
[j
].fce
== fce
)
8129 if (j
< MAX_OPEN_CACHED_FILES
)
8130 continue; /* Cached file is still open */
8131 if (fce
->used
< oldest_u
)
8134 oldest_u
= file_cache
[i
].used
;
8140 done
= 1; /* We can flush nothing more */
8143 discard_cached_file(oldest_e
);
8144 done
= (file_cache_size
+ needed
) <= max_file_cache_size
;
8151 | Locate the specified file within the cache.
8152 | Returns NULL if the file is not cached
8154 static FileCacheEntry
*find_cached_file(char *name
)
8157 FileCacheEntry
*fce
= file_cache
;
8159 for (i
= 0; i
< MAX_CACHE_ENTRIES
; i
++, fce
++)
8162 if (streq(fce
->name
, name
))
8170 /*--------------------------------------------------------------------------*/
8171 /* Externally visible file cache stuff */
8172 /*--------------------------------------------------------------------------*/
8176 | Returns the file cache handle of the file, or NULL for failure.
8177 | Note that if mode is anything other than "r" the call defers to
8180 | NB: The returned handle is almost certainly *NOT* a |FILE*|
8181 | (although it may be if the cache cannot accomodate the file).
8183 | Therefore, you *MUST* ensure that any file opened with cached_fopen()
8184 | is only ever accessed via cached_fgets() and cached_fclose().
8186 | Failure to do so will result in, ahem, unpleasantness. Extreme
8189 FILE *cached_fopen(char *name
, char *mode
)
8191 FileCacheEntry
*fcs
= NULL
;
8194 if (strcmp(mode
, "r") || !use_filecache
)
8195 return my_fopen(name
, mode
);
8197 if (!file_cache_initd
)
8202 if (max_file_cache_size
>= 0)
8204 /* Find a free cache entry */
8205 for (fch
= 0; fch
< MAX_OPEN_CACHED_FILES
; fch
++)
8206 if (!cached_file_handle
[fch
].fce
)
8209 /* Out of handles? */
8210 if (fch
>= MAX_OPEN_CACHED_FILES
)
8211 return my_fopen(name
, mode
);
8213 /* Is the file already cached? */
8214 fcs
= find_cached_file(name
);
8217 /* File wasn't cached, so cache it */
8218 flush_file_cache(NULL
); /* Clean stuff out of the cache if need be */
8219 fcs
= cache_file(name
); /* Cache the new file */
8220 flush_file_cache(fcs
); /* Flush, but keep the latest file */
8224 /* Did we fail to cache the file? */
8227 return my_fopen(name
, mode
);
8230 /* File was cached OK */
8231 cached_file_handle
[fch
].ptr
= fcs
->text
; /* Init sequential pointer */
8232 cached_file_handle
[fch
].fce
= fcs
; /* Cache block pointer */
8233 fcs
->used
= fc_access_counter
++; /* Opening the file counts as an access */
8235 return (FILE *)(&cached_file_handle
[fch
]);
8242 errr
cached_fclose(FILE *fch_
)
8244 CachedFileHandle
*fch
;
8246 /* Is the FILE* genuine? */
8247 if ((fch_
< (FILE *)cached_file_handle
) || (fch_
> max_cfh_addr
))
8248 return my_fclose(fch_
);
8250 fch
= (CachedFileHandle
*) fch_
;
8252 /* Check for "Ooopses": */
8253 if (fch
->fce
== NULL
)
8254 core("cached_fclose called on a non-open file handle");
8256 flush_file_cache(NULL
); /* Clean out the cache if need be */
8257 fch
->fce
= NULL
; /* Mark file handle as inactive */
8264 | Do the my_fgets thing on a file
8266 errr
cached_fgets(FILE *fch_
, char *buffer
, int max_len
)
8268 CachedFileHandle
*fch
;
8272 /* Is the FILE* genuine? */
8273 if ((fch_
< (FILE *)cached_file_handle
) || (fch_
> max_cfh_addr
))
8274 return my_fgets(fch_
, buffer
, max_len
);
8276 fch
= (CachedFileHandle
*) fch_
;
8278 /* Check for "Oopses": */
8279 if (!file_cache_initd
)
8280 core("cached_fgets() on uninitialised file-cache");
8282 core("cached_fgets called for a un-open file");
8284 eof
= fch
->fce
->eof
;
8287 /* Out of bounds? */
8294 | Read the next line, up to \0 (which would have v=been \n in the original file),
8295 | or max_len-1 characters
8297 if (fch
->fce
->compressed
)
8298 ptr
+= decompress_string(buffer
, ptr
, max_len
);
8301 if (eof
- ptr
< max_len
)
8303 max_len
= eof
- ptr
;
8305 for (; max_len
>= 1; max_len
--)
8306 if ((*buffer
++ = *ptr
++) == 0)
8308 *buffer
= 0; /* terminate (paranoia) */
8311 /* Update sequential pointer */
8317 #endif /* USE_FILECACHE */
8321 | This section deals with checking that the .raw files are up to date
8322 | wrt to the .txt files.
8324 | For this to work, the equivalent function (in init2.c) needs to be
8325 | #if-d out (and this function should be declared). You'll probably
8326 | also need to zap the UNIX #includes at the top of the file
8329 extern errr
check_modification_date(int fd
, cptr template_file
)
8336 /* Use OS_Args 7 to find out the pathname 'fd' refers to */
8337 e
= SWI(6, 0, SWI_OS_Args
,
8339 7, /* Get path from filehandle */
8340 fd
, /* file handle */
8341 raw_buf
, /* buffer */
8343 1024 /* size of buffer */
8344 /* No output regs used */
8351 /* Build the path to the template_file */
8352 path_build(txt_buf
, sizeof(txt_buf
), ANGBAND_DIR_EDIT
, template_file
);
8354 i
= file_is_newer(riscosify_name(txt_buf
), raw_buf
);
8360 /* Alarm functions */
8361 static int alarm_ackd
= 0; /* has the alarm been acknowledged? */
8362 static window_handle aw
= 0; /* alarm window */
8365 | Is the alarm due to go off, ie. is it enabled, and if so
8366 | does the current time match the alarm time?
8368 static void check_alarm()
8373 alarm_lastcheck
= Time_Monotonic();
8377 if (lt
->tm_hour
== alarm_h
&& lt
->tm_min
== alarm_m
)
8379 if (!alarm_ackd
) alarm_disp
= 1;
8386 /* Hack: if the alarm has already been acknowledged then don't re-trigger it */
8392 /* Hack: if the alarm should make a noise, then make one: */
8393 if (alarm_disp
&& alarm_beep
== 1)
8395 static unsigned int last_beep
= 0;
8396 unsigned int t
= Time_Monotonic();
8397 if (t
> last_beep
+ 100)
8405 | If we're in the desktop then fire the alarm off if need be.
8406 | If we aren't then do nothing - the fullscreen bored() function
8407 | will take care of the alarm.
8409 #ifndef FULLSCREEN_ONLY
8410 if (!fullscreen_font
&& alarm_disp
)
8411 trigger_alarm_desktop();
8412 #endif /* FULLSCREEN_ONLY */
8416 static void ack_alarm(void)
8426 if (alarm_type
== 3)
8428 /* One shot alarm */
8430 write_alarm_choices();
8435 #ifndef FULLSCREEN_ONLY
8437 | Click in the (desktop) alarm window
8439 static BOOL
Hnd_AlarmClick(event_pollblock
* pb
, void *ref
)
8447 | The alarm has gone off in the desktop
8449 static void trigger_alarm_desktop(void)
8455 aw
= Window_Create("alarm", template_TITLEMIN
);
8456 if (!aw
) core("failed to create Alarm window!");
8458 sprintf(buffer
, "Alarm from %s", VARIANT
);
8459 Window_SetTitle(aw
, buffer
);
8460 Event_Claim(event_CLICK
, aw
, 0, Hnd_AlarmClick
, NULL
);
8461 Event_Claim(event_CLOSE
, aw
, event_ANY
, Hnd_AlarmClick
, NULL
);
8463 Icon_printf(aw
, 1, "An alarm was set for %02d:%02d", alarm_h
, alarm_m
);
8464 Icon_SetText(aw
, 2, alarm_message
);
8465 Window_Show(aw
, open_CENTERED
);
8468 #endif /* FULLSCREEN_ONLY */
8471 /*--------------------------------------------------------------------------*/
8473 #ifndef FE_DEBUG_INFO
8474 static void show_debug_info(void)
8476 core("main-acn internal logic error 004");
8480 static int debug_cx
= 0;
8481 static int debug_cy
= 0;
8482 static int debug_cl
= COL(WHITE
);
8483 static int debug_sl
= 0;
8486 static void debug_cls(void)
8489 debug_cx
= debug_cy
= debug_sl
= 0;
8492 static void debug_tcol(int c
)
8498 static void debug_scroll(void)
8500 char **c
= ((term_data
*)Term
)->t
.scr
->c
; /* char array */
8501 byte
**a
= ((term_data
*)Term
)->t
.scr
->a
; /* attr array */
8508 for (y
= 1; y
< 23; y
++)
8510 for (x
= p
= 0; x
< 80; x
++)
8515 Term_putstr(x
- p
, y
- 1, p
, cc
, tmp
);
8521 Term_putstr(x
- p
, y
- 1, p
, cc
, tmp
);
8524 Term_erase(0, 22, 80);
8528 static void debug_print_line(char *l
)
8533 /* Handle scrolling */
8540 PUT_FSTR(0, 23, COL(YELLOW
), "[RET one line, SPC one page]");
8545 while (k
!= 32 && k
!= 13);
8546 Term_erase(0, 23, 79);
8547 debug_sl
= k
== 32 ? 21 : 0;
8552 /* Hack: check for NL */
8553 for (le
= l
; *le
; le
++)
8561 Term_putstr(debug_cx
, debug_cy
, le
- l
, debug_cl
, l
);
8566 debug_cx
+= (le
- l
);
8578 Term_gotoxy(debug_cx
, debug_cy
);
8583 static int debug_next_line(char *lb
, char **t
, int cx
)
8593 while (*lt
&& cx
< 80)
8597 if (lb
[i
] == '\n') /* New line */
8599 cx
= 0; /* Cursor x will be 0 after displaying */
8600 i
++; /* Keep the \n in the output */
8601 break; /* All done */
8603 else if (lb
[i
] == '\t') /* Tab */
8615 else /* Anything else */
8622 lb
[i
] = 0; /* terminate line buffer */
8623 *t
= lt
; /* update text pointer */
8624 return cx
; /* return cursor x after printing */
8627 static void debug_printf(char *fmt
, ...)
8635 vstrnfmt(buffer
, sizeof(buffer
), fmt
, ap
);
8638 /* Now split the string into display lines */
8639 while (debug_next_line(line
, &p
, debug_cx
) >= 0)
8640 debug_print_line(line
);
8644 static void debug_version_info(void)
8646 debug_tcol(COL(YELLOW
));
8648 debug_printf("\n\nMisc. Info:\n");
8649 debug_tcol(COL(WHITE
));
8650 debug_printf("\tVariant name = \"%s\"\n", VARIANT
);
8651 debug_printf("\tFront-end version: %s\n", PORTVERSION
);
8652 debug_printf("\tFront-end compiled: %s %s\n", __TIME__
, __DATE__
);
8653 debug_printf("\tCompile time flags:\n");
8655 #ifdef USE_FILECACHE
8656 debug_printf("\t\tUSE_FILECACHE\n");
8659 #ifdef ABBR_FILECACHE
8660 debug_printf("\t\tABBR_FILECACHE\n");
8663 #ifdef SMART_FILECACHE
8664 debug_printf("\t\tSMART_FILECACHE\n");
8667 debug_tcol(COL(YELLOW
));
8668 debug_printf("\nResource path:\n");
8669 debug_tcol(COL(WHITE
));
8670 debug_printf("\t\"%s\"\n", resource_path
);
8672 debug_tcol(COL(YELLOW
));
8673 debug_printf("\nTempfile path:\n");
8674 debug_tcol(COL(WHITE
));
8675 debug_printf("\t\"%s\"\n", scrap_path
);
8676 debug_printf("\tScrapfiles are %s deleted at exit.\n",
8677 (flush_scrap
? "" : "NOT"));
8679 debug_tcol(COL(YELLOW
));
8680 debug_printf("\nChoices files:\n");
8681 debug_tcol(COL(L_BLUE
));
8682 debug_printf("\tDesired files:\n");
8683 debug_tcol(COL(WHITE
));
8684 debug_printf("\tPrimary (r/w): \"%s\"\n", choices_file
[CHFILE_WRITE
]);
8685 debug_printf("\t Fallback (r): \"%s\"\n", choices_file
[CHFILE_READ
]);
8686 debug_printf("\t Mirror (r/w): \"%s\"\n", choices_file
[CHFILE_MIRROR
]);
8687 debug_tcol(COL(L_BLUE
));
8688 debug_printf("\tActual files:\n");
8689 debug_tcol(COL(WHITE
));
8690 debug_printf("\t Write: \"%s\"\n", find_choices(TRUE
));
8691 debug_printf("\t Read: \"%s\"\n", find_choices(FALSE
));
8693 debug_tcol(COL(YELLOW
));
8694 debug_printf("\nAlarm files:\n");
8695 debug_tcol(COL(L_BLUE
));
8696 debug_printf("\tDesired files:\n");
8697 debug_tcol(COL(WHITE
));
8698 debug_printf("\tPrimary (r/w): \"%s\"\n", alarm_file
[CHFILE_WRITE
]);
8699 debug_printf("\t Fallback (r): \"%s\"\n", alarm_file
[CHFILE_READ
]);
8700 debug_tcol(COL(L_BLUE
));
8701 debug_printf("\tActual files:\n");
8702 debug_tcol(COL(WHITE
));
8703 debug_printf("\t Write: \"%s\"\n", find_alarmfile(TRUE
));
8704 debug_printf("\t Read: \"%s\"\n", find_alarmfile(FALSE
));
8706 debug_tcol(COL(YELLOW
));
8707 debug_printf("\nDynamic areas:\n");
8708 debug_tcol(COL(WHITE
));
8709 debug_printf("\tFontcache DA = %d\t", font_area
);
8710 debug_printf("size = %d\theap size = %d\n", font_area_size
, font_heap_size
);
8711 debug_printf("\t ralloc DA = %d\t", game_area
);
8712 debug_printf("size = %d\theap size = %d\n", game_area_size
, game_heap_size
);
8717 static void debug_filecache_info(void)
8719 #ifndef USE_FILECACHE
8720 debug_tcol(COL(L_DARK
));
8721 debug_printf("File cache disabled at compile time.\n");
8726 cf
= cs
= ucs
= j
= k
= 0; /* To stop an usused warning if USE_FILECACHE is undefined */
8727 t
= strlen(resource_path
);
8729 if (!file_cache_initd
)
8733 debug_tcol(COL(YELLOW
));
8734 debug_printf("\nFilecache contents:\n");
8735 debug_tcol(COL(L_BLUE
));
8736 debug_printf("Flags: Smart=%d; Abbrv=%d; Slave=%d; Enable=%d\n",
8737 smart_filecache
, abbr_filecache
, abbr_tmpfile
, use_filecache
);
8738 debug_tcol(COL(SLATE
));
8739 if (smart_filecache
|| abbr_filecache
)
8740 debug_printf("\t\t%3s %6s/%-6s %6s %6s Path (relative to lib/)\n",
8741 "Hnd", "Cache", "Disc", "Time", "Status");
8743 debug_printf("\t\t%3s %6s %6s %6s Path (relative to lib/)\n", "Hnd",
8744 "Size", "Time", "Status");
8746 for (j
= 0; j
< MAX_CACHE_ENTRIES
; j
++)
8748 FileCacheEntry
*fce
= &(file_cache
[j
]);
8752 debug_tcol(COL(L_GREEN
));
8753 debug_printf("\t\t%3d ", j
);
8754 debug_tcol(COL(L_UMBER
));
8755 if (!smart_filecache
&& !abbr_filecache
)
8756 debug_printf("%6d ", fce
->eof
- fce
->text
);
8759 debug_printf("%6d/", fce
->eof
- fce
->text
);
8760 k
= File_Size(riscosify_name(fce
->name
));
8761 debug_printf("%-6d ", k
);
8767 cs
+= fce
->eof
- fce
->text
;
8768 debug_printf("%6d ", fce
->used
);
8769 for (k
= 0; k
< MAX_OPEN_CACHED_FILES
; k
++)
8770 if (cached_file_handle
[k
].fce
== fce
)
8772 debug_tcol(COL(RED
));
8773 debug_printf("%-6s ", k
< MAX_OPEN_CACHED_FILES
? "Open" : "");
8774 debug_tcol(COL(L_UMBER
));
8775 debug_printf("%s\n", fce
->name
+ t
);
8779 debug_tcol(COL(L_BLUE
));
8780 debug_printf("\tTotal:\t%3d ", cf
);
8782 debug_printf("%6d/%-6d\n", cs
, ucs
);
8784 debug_printf("%6d\n", cs
);
8785 debug_tcol(COL(BLUE
));
8786 #endif /* USE_FILECACHE */
8790 static void show_debug_info(void)
8793 /* blank the term */
8796 /* Repeatedly prompt for a command */
8799 debug_tcol(COL(VIOLET
));
8800 debug_printf("\nInfo: (V)ersion, (F)ilecache, ESC=exit ");
8806 case 'v': case 'V': debug_version_info();
8808 case 'f': case 'F': debug_filecache_info
8822 #endif /* FE_DEBUG_INFO */
8824 #endif /* __riscos */