/* File: main-xxx.c */ /* Purpose: Sample visual module for Angband 2.7.9 */ /* * This file written by "Ben Harrison (benh@voicenet.com)". * * This file is intended to show one way to build a "visual module" * for Angband to allow it to work with a new system. It does not * actually work, but if the "XXX XXX XXX" comments were replaced * with functional code, then it probably would. * * See "term.c" for info on the concept of the "generic terminal", * and for more comments about what this file must supply. * * Basically, there are three ways to port Angband to a new system, * first, to modify the "main-gcu.c" file to support a version of * "curses" on your machine, second, to write a new "main-xxx.c" * file that works in a similar fashion to "main-gcu.c" but which * has its own "USE_XXX" define and its own "activation" code in * "main.c", and third, to write a new "main-xxx.c" file that works * in a similar manner to "main-mac.c" or "main-win.c" and which * replaces the "main.c" file entirely. The second and third ways * are shown in this file, based on the "USE_XXX" define. If you * are using the "USE_XXX" method, and it is possible to include * this file without "USE_XXX" being defined, then you should * uncomment the "#ifdef USE_XXX" below, and the "#endif" at the * end of the file. * * Note that the "util.c" file often contains functions which must * be modified in small ways for various platforms, for example, * the "delay()" function often needs to be rewritten. * * When you complete a port to a new system, you should email both * your new files (if any), and any changes you needed to make to * existing files, including "h-config.h", "config.h", and any of * the "Makefile" files, to me (benh@voicenet.com) for inclusion * in the next version. * * Try to stick to a "three letter" naming scheme for "main-xxx.c" * and "Makefile.xxx" and such for consistency. */ #include "angband.h" /* #ifdef USE_XXX */ /* * Extra data to associate with each "window" * * Each "window" is represented by a "term_data" structure, which * contains a "term" structure, which contains a pointer (t->data) * back to the term_data structure. */ typedef struct term_data term_data; struct term_data { term t; cptr name; /* XXX XXX XXX */ /* Other fields if needed */ }; /* * One "term_data" for each "window" * * XXX XXX XXX The only "window" which you MUST support is the * main "term_screen" window, the rest are optional. If you only * support a single window, then most of the junk involving the * "term_data" structures is actually not needed, since you can * use global variables. But you should avoid global variables * when possible as a general rule... */ static term_data screen; static term_data mirror; static term_data recall; static term_data choice; #if 0 /* Fix the syntax below */ /* * XXX XXX XXX The "color" array for the visual module * * This table should be used in whetever way is necessary to * convert the Angband Color Indexes into the proper "color data" * for the visual system. On the Macintosh, these are arrays of * three shorts, on the IBM, these are combinations of the eight * basic color codes with optional "bright" bits, on X11, these * are actual "pixel" codes extracted from another table which * contains textual color names. * * The Angband Color Set (0 to 15): * Black, White, Slate, Orange, Red, Blue, Green, Umber * D-Gray, L-Gray, Violet, Yellow, L-Red, L-Blue, L-Green, L-Umber * * Colors 8 to 15 are basically "enhanced" versions of Colors 0 to 7. * * As decribed in one of the header files, in a perfect world, the * colors below should fit a nice clean "quartered" specification * in RGB codes, but this must often be Gamma Corrected. The 1/4 * parts of each Red,Green,Blue are shown in the comments below, * again, these values are *before* gamma correction. */ static local_color_data_type color_data[16] = { /* XXX XXX XXX 0,0,0 */, /* TERM_DARK */ /* XXX XXX XXX 4,4,4 */, /* TERM_WHITE */ /* XXX XXX XXX 2,2,2 */, /* TERM_SLATE */ /* XXX XXX XXX 4,2,0 */, /* TERM_ORANGE */ /* XXX XXX XXX 3,0,0 */, /* TERM_RED */ /* XXX XXX XXX 0,2,1 */, /* TERM_GREEN */ /* XXX XXX XXX 0,0,4 */, /* TERM_BLUE */ /* XXX XXX XXX 2,1,0 */, /* TERM_UMBER */ /* XXX XXX XXX 1,1,1 */, /* TERM_L_DARK */ /* XXX XXX XXX 3,3,3 */, /* TERM_L_WHITE */ /* XXX XXX XXX 4,0,4 */, /* TERM_VIOLET */ /* XXX XXX XXX 4,4,0 */, /* TERM_YELLOW */ /* XXX XXX XXX 4,0,0 */, /* TERM_L_RED */ /* XXX XXX XXX 0,4,0 */, /* TERM_L_GREEN */ /* XXX XXX XXX 0,4,4 */, /* TERM_L_BLUE */ /* XXX XXX XXX 3,2,1 */ /* TERM_L_UMBER */ }; #endif /*** Special functions ***/ #ifndef USE_XXX /* * XXX XXX XXX You may need an event handler here */ #endif /*** Function hooks needed by "Term" ***/ /* * XXX XXX XXX Init a new "term" * * This function should do whatever is necessary to prepare a new "term" * for use by the "term.c" package. This may include clearing the window, * preparing the cursor, setting the font/colors, etc. Usually, this * function does nothing, and the "init_xxx()" function does it all. */ static void Term_init_xxx(term *t) { term_data *td = (term_data*)(t->data); /* XXX XXX XXX */ } /* * XXX XXX XXX Nuke an old "term" * * This function is called when an old "term" is no longer needed. It should * do whatever is needed to clean up before the program exits, such as wiping * the screen, restoring the cursor, fixing the font, etc. Often this function * does nothing and lets the operating system clean up when the program quits. */ static void Term_nuke_xxx(term *t) { term_data *td = (term_data*)(t->data); /* XXX XXX XXX */ } /* * XXX XXX XXX Do a "user action" on the current "term" * * This function allows the visual module to do things. * * This function is currently unused, but has access to the "info" * field of the "term" to hold an extra argument. * * In general, this function should return zero if the action is successfully * handled, and non-zero if the action is unknown or incorrectly handled. */ static errr Term_user_xxx(int n) { term_data *td = (term_data*)(Term->data); /* XXX XXX XXX Handle the request */ /* Unknown */ return (1); } /* * XXX XXX XXX Do a "special thing" to the current "term" * * This function must react to a large number of possible arguments, each * corresponding to a different "action request" by the "term.c" package. * * The "action type" is specified by the first argument, which must be a * constant of the form "TERM_XTRA_*" as given in "term.h", and the second * argument specifies the "information" for that argument, if any, and will * vary according to the first argument. * * In general, this function should return zero if the action is successfully * handled, and non-zero if the action is unknown or incorrectly handled. */ static errr Term_xtra_xxx(int n, int v) { term_data *td = (term_data*)(Term->data); /* Analyze */ switch (n) { case TERM_XTRA_EVENT: /* XXX XXX XXX Process some pending events */ /* Wait for at least one event if "v" is non-zero */ /* otherwise, if no events are ready, return at once. */ /* When "keypress" events are encountered, the "ascii" */ /* value corresponding to the key should be sent to the */ /* "Term_keypress()" function. Certain "bizarre" keys, */ /* such as function keys or arrow keys, may send special */ /* sequences of characters, such as control-underscore, */ /* plus letters corresponding to modifier keys, plus an */ /* underscore, plus carriage return, which can be used by */ /* the main program for "macro" triggers. This action */ /* should handle as many events as is efficiently possible */ /* but is only required to handle a single event, and then */ /* only if one is ready or "v" is true */ /* This action is required. */ return (0); case TERM_XTRA_FLUSH: /* XXX XXX XXX Flush all pending events */ /* This action should handle all events waiting on the */ /* queue, optionally discarding all "keypress" events, */ /* since they will be discarded anyway in "term.c". */ /* This action is required, but is often not "essential". */ return (0); case TERM_XTRA_CLEAR: /* XXX XXX XXX Clear the entire window */ /* This action should clear the entire window, and redraw */ /* any "borders" or other "graphic" aspects of the window. */ /* This action is required. */ return (0); case TERM_XTRA_SHAPE: /* XXX XXX XXX Set the cursor visibility (optional) */ /* This action should change the visibility of the cursor, */ /* if possible, to the requested value (0=off, 1=on) */ /* This action is optional, but can improve both the */ /* efficiency (and attractiveness) of the program. */ return (0); case TERM_XTRA_FROSH: /* XXX XXX XXX Flush a row of output (optional) */ /* This action should make sure that row "v" of the "output" */ /* to the window will actually appear on the window. */ /* This action is optional on most systems. */ return (0); case TERM_XTRA_FRESH: /* XXX XXX XXX Flush output (optional) */ /* This action should make sure that all "output" to the */ /* window will actually appear on the window. */ /* This action is optional if all "output" will eventually */ /* show up on its own, or when actually requested. */ return (0); case TERM_XTRA_NOISE: /* XXX XXX XXX Make a noise (optional) */ /* This action should produce a "beep" noise. */ /* This action is optional, but nice. */ return (0); case TERM_XTRA_SOUND: /* XXX XXX XXX Make a sound (optional) */ /* This action should produce sound number "v", where */ /* the "name" of that sound is "sound_names[v]". */ /* This action is optional, and not important. */ return (0); case TERM_XTRA_BORED: /* XXX XXX XXX Handle random events when bored (optional) */ /* This action is optional, and not important */ return (0); case TERM_XTRA_REACT: /* XXX XXX XXX React to global changes (optional) */ /* For example, this action can be used to react to */ /* changes in the global "color_table[256][4]" array. */ /* This action is optional, but can be very useful */ return (0); case TERM_XTRA_ALIVE: /* XXX XXX XXX Change the "hard" level (optional) */ /* This action is used if the program changes "aliveness" */ /* by being either "suspended" (v=0) or "resumed" (v=1) */ /* This action is optional, unless the computer uses the */ /* same "physical screen" for multiple programs, in which */ /* case this action should clean up to let other programs */ /* use the screen, or resume from such a cleaned up state. */ /* This action is currently only used on UNIX machines */ return (0); case TERM_XTRA_LEVEL: /* XXX XXX XXX Change the "soft" level (optional) */ /* This action is used when the term window changes "activation" */ /* either by becoming "inactive" (v=0) or "active" (v=1) */ /* This action is optional but can be used to do things like */ /* activate the proper font / drawing mode for the newly active */ /* term window. This action should NOT change which window has */ /* the "focus", which window is "raised", or anything like that. */ /* This action is optional if all the other things which depend */ /* on what term is active handle activation themself. */ return (0); } /* Unknown or Unhandled action */ return (1); } /* * XXX XXX XXX Erase some characters * * This function should erase "n" characters starting at (x,y). * * You may assume "valid" input if the window is properly sized. */ static errr Term_wipe_xxx(int x, int y, int n) { term_data *td = (term_data*)(Term->data); /* XXX XXX XXX Erase the block of characters */ /* Success */ return (0); } /* * XXX XXX XXX Display the cursor * * This routine should display the cursor at the given location * (x,y) in some manner. On some machines this involves actually * moving the physical cursor, on others it involves drawing a fake * cursor in some form of graphics mode. Note the "soft_cursor" * flag which tells "term.c" to treat the "cursor" as a "visual" * thing and not as a "hardware" cursor. * * You may assume "valid" input if the window is properly sized. * * You may use the "Term_grab(x, y, &a, &c)" function, if needed, * to determine what attr/char should be "under" the new cursor, * for "inverting" purposes or whatever. */ static errr Term_curs_xxx(int x, int y) { term_data *td = (term_data*)(Term->data); /* XXX XXX XXX Display a cursor (see above) */ /* Success */ return (0); } /* * XXX XXX XXX Draw a "picture" on the screen * * This routine should display the given attr/char pair at the * given location (x,y). This function is only used if one of * the flags "always_pict" or "higher_pict" is defined. * * You must be sure that the attr/char pair, when displayed, will * erase anything (including any visual cursor) that used to be * at the given location. On many machines this is automatic, on * others, you must first call "Term_wipe_xxx(x, y, 1)". * * With the "higher_pict" flag, this function can be used to allow * the display of "pseudo-graphic" pictures, for example, by using * "(a&0x7F)" as a "row" and "(c&0x7F)" as a "column" to index into * a special auxiliary pixmap of special pictures. * * With the "always_pict" flag, this function can be used to force * every attr/char pair to be drawn one at a time, instead of trying * to "collect" the attr/char pairs into "strips" with similar "attr" * codes, which would be sent to "Term_text_xxx()". */ static errr Term_pict_xxx(int x, int y, byte a, char c) { term_data *td = (term_data*)(Term->data); /* XXX XXX XXX Draw a "picture" */ /* Success */ return (0); } /* * XXX XXX XXX Display some text on the screen * * This function should actually display a string of characters * starting at the given location, using the given "attribute", * and using the given string of characters, which is terminated * with a nul character and which has exactly "n" characters. * * You may assume "valid" input if the window is properly sized. * * You must be sure that the string, when written, erases anything * (including any visual cursor) that used to be where the text is * drawn. On many machines this happens automatically, on others, * you must first call "Term_wipe_xxx()" to clear the area. * * You may ignore the "color" parameter if you are only supporting * a monochrome environment, unless you have set the "draw_blanks" * flag, since this routine is normally never called to display * "black" (invisible) text, and all other colors should be drawn * in the "normal" color in a monochrome environment. * * Note that this function must correctly handle "black" text if * the "always_text" flag is set, if this flag is not set, all the * "black" text will be handled by the "Term_wipe_xxx()" hook. */ static errr Term_text_xxx(int x, int y, int n, byte a, cptr s) { term_data *td = (term_data*)(Term->data); /* XXX XXX XXX Normally use color "color_data[a & 0x0F]" */ /* XXX XXX XXX Draw the string */ /* Success */ return (0); } /* * XXX XXX XXX Instantiate a "term_data" structure * * This is one way to prepare the "term_data" structures and to * "link" the various informational pieces together. * * This function assumes that every window should be 80x24 in size * (the standard size) and should be able to queue 256 characters. * Technically, only the "main screen window" needs to queue any * characters, but this method is simple. * * Note that "activation" calls the "Term_init_xxx()" hook for * the "term" structure, if needed. */ static void term_data_link(term_data *td) { term *t = &td->t; /* Initialize the term */ term_init(t, 80, 24, 256); /* XXX XXX XXX Choose "soft" or "hard" cursor */ /* A "soft" cursor must be explicitly "drawn" by the program */ /* while a "hard" cursor has some "physical" existance and is */ /* moved whenever text is drawn on the screen. See "term.c". */ /* t->soft_cursor = TRUE; */ /* XXX XXX XXX Avoid the "corner" of the window */ /* t->icky_corner = TRUE; */ /* XXX XXX XXX Use "Term_pict()" for all data */ /* See the "Term_pict_xxx()" function above. */ /* t->always_pict = TRUE; */ /* XXX XXX XXX Use "Term_pict()" for "special" data */ /* See the "Term_pict_xxx()" function above. */ /* t->higher_pict = TRUE; */ /* XXX XXX XXX Use "Term_text()" for all data */ /* See the "Term_text_xxx()" function above. */ /* t->always_text = TRUE; */ /* XXX XXX XXX Ignore the "TERM_XTRA_BORED" action */ /* This may make things slightly more efficient. */ /* t->never_bored = TRUE; */ /* XXX XXX XXX Ignore the "TERM_XTRA_FROSH" action */ /* This may make things slightly more efficient. */ /* t->never_frosh = TRUE; */ /* Erase with "white space" */ t->attr_blank = TERM_WHITE; t->char_blank = ' '; /* Prepare the init/nuke hooks */ t->init_hook = Term_init_xxx; t->nuke_hook = Term_nuke_xxx; /* Prepare the template hooks */ t->user_hook = Term_user_xxx; t->xtra_hook = Term_xtra_xxx; t->wipe_hook = Term_wipe_xxx; t->curs_hook = Term_curs_xxx; t->pict_hook = Term_pict_xxx; t->text_hook = Term_text_xxx; /* Remember where we came from */ t->data = (vptr)(td); /* Activate it */ Term_activate(t); } #ifdef USE_XXX /* * A "normal" system uses "main.c" for the "main()" function, and * simply adds a call to "init_xxx()" to that function, conditional * on some form of "USE_XXX" define. */ /* * XXX XXX XXX Initialization function */ void init_xxx(void) { term_data *td; /* XXX XXX XXX Initialize the system */ /* Recall window */ td = &recall; WIPE(td, term_data); td->name = "Recall"; /* XXX XXX XXX Extra stuff */ term_data_link(&recall); term_recall = &recall.t; /* Choice window */ td = &choice; WIPE(td, term_data); td->name = "Choice"; /* XXX XXX XXX Extra stuff */ term_data_link(&choice); term_choice = &choice.t; /* Mirror window */ td = &mirror; WIPE(td, term_data); td->name = "Mirror"; /* XXX XXX XXX Extra stuff */ term_data_link(&mirror); term_mirror = &mirror.t; /* Screen window */ td = &screen; WIPE(td, term_data); td->name = "Screen"; /* XXX XXX XXX Extra stuff */ term_data_link(&screen); term_screen = &screen.t; } #else /* USE_XXX */ /* * Some special machines need their own "main()" function, which they * can provide here, making sure NOT to compile the "main.c" file. * * These systems usually have some form of "event loop", run forever * as the last step of "main()", which handles things like menus and * window movement, and calls "play_game(FALSE)" to load a game after * initializing "savefile" to a filename, or "play_game(TRUE)" to make * a new game. The event loop would also be triggered by "Term_xtra()" * (the TERM_XTRA_EVENT action), in which case the event loop would not * actually "loop", but would run once and return. */ /* * Init some stuff * * This function is needed to keep the "path" variable off the stack. */ static void init_stuff(void) { char path[1024]; /* XXX XXX XXX Prepare the path */ /* This must in some way prepare the "path" variable */ /* so that it points at the "lib" directory. Every machine */ /* handles this in a different way */ strcpy(path, "XXX XXX XXX"); /* Prepare the filepaths */ init_file_paths(path); } /* * Main function */ void main(void) { term_data *td; /* XXX XXX XXX Initialize the machine */ /* Recall window */ td = &recall; WIPE(td, term_data); td->name = "Recall"; /* XXX XXX XXX Extra stuff */ term_data_link(&recall); term_recall = &recall.t; /* Choice window */ td = &choice; WIPE(td, term_data); td->name = "Choice"; /* XXX XXX XXX Extra stuff */ term_data_link(&choice); term_choice = &choice.t; /* Mirror window */ td = &mirror; WIPE(td, term_data); td->name = "Mirror"; /* XXX XXX XXX Extra stuff */ term_data_link(&mirror); term_mirror = &mirror.t; /* Screen window */ td = &screen; WIPE(td, term_data); td->name = "Screen"; /* XXX XXX XXX Extra stuff */ term_data_link(&screen); term_screen = &screen.t; /* Initialize some stuff */ init_stuff(); /* Display the "news" screen */ show_news(); /* Initialize some arrays */ init_some_arrays(); /* XXX XXX XXX Hack -- assume wizard permissions */ can_be_wizard = TRUE; /* XXX XXX XXX Hack -- Use the "pref-xxx.prf" file */ ANGBAND_SYS = "xxx"; /* XXX XXX XXX Event loop forever */ while (TRUE) /* Handle Events */; } #endif /* USE_XXX */ #endif