/* File: borg9.c */ /* Purpose: Highest level functions for the Borg -BEN- */ #include "angband.h" #ifdef ALLOW_BORG #include "borg1.h" #include "borg2.h" #include "borg3.h" #include "borg4.h" #include "borg5.h" #include "borg6.h" #include "borg7.h" #include "borg8.h" #include "borg9.h" bool borg_cheat_death; /* * This file implements the "Ben Borg", an "Automatic Angband Player". * * This version of the "Ben Borg" is designed for use with Angband 2.7.9v6. * * Use of the "Ben Borg" requires re-compilation with ALLOW_BORG defined, * and with the various "borg*.c" files linked into the executable. * * Note that you can only use the Borg if your character has been marked * as a "Borg User". You can do this, if necessary, by responding "y" * when asked if you really want to use the Borg. This will (normally) * result in your character being inelligible for the high score list. * * The "do_cmd_borg()" function, called when the user hits "^Z", allows * the user to interact with the Borg. You do so by typing "Borg Commands", * including 'z' to activate (or re-activate), 'K' to show monsters, 'T' to * show objects, 'd' to toggle "demo mode", 'f' to open/shut the "log file", * 'i' to display internal flags, etc. See "do_cmd_borg()" for more info. * * The first time you enter a Borg command, the Borg is initialized. This * consists of three major steps, and requires at least 400K of free memory, * if the memory is not available, the game may abort. * * (1) The various "borg" modules are initialized. * * (2) Some important "state" information is extracted, including the level * and race/class of the player, and some more initialization is done. * * (3) Some "historical" information (killed uniques, maximum dungeon depth) * is "stolen" from the game. * * When the Ben Borg is "activated", it uses the "Term_inkey_hook" to steal * control from the user. Later, if it detects any input from the real user, * it gracefully relinquishes control by clearing the "Term_inkey_hook" after * any pending key-sequences are complete. * * The Borg will abort if it detects any "errors", or if it detects any * "situations" such as "death", or if it detects any "panic" situations, * such as "imminent death", if the appropriate flags are set. * * The Ben Borg is only supposed to "know" what is visible on the screen, * which it learns by using the "term.c" screen access function "Term_what()", * the cursor location function "Term_locate()", and the cursor visibility * extraction function "Term_get_cursor()". * * The Ben Borg is only supposed to "send" keypresses when the "Term_inkey()" * function asks for a keypress, which is accomplished by using a special * function hook in the "z-term.c" file, which allows the Borg to "steal" * control from the "Term_inkey()" and "Term_flush()" functions. This * allows the Ben Borg to pretend to be a normal user. * * Note that if properly designed, the Ben Borg could be run as an external * process, which would actually examine the screen (or pseudo-terminal), * and send keypresses directly to the keyboard (or pseudo-terminal). Thus * it should never access any "game variables", unless it is able to extract * those variables for itself by code duplication or complex interactions, * or, in certain situations, if those variables are not actually "required". * * Currently, the Ben Borg is a few steps away from being able to be run as * an external process, primarily in the "low level" details, such as knowing * when the game is ready for a keypress. Also, the Ben Borg assumes that a * character has already been rolled, and maintains no state between saves, * which is partially offset by "cheating" to "acquire" the maximum dungeon * depth, without which equipment analysis will be faulty. * * The "theory" behind the Borg is that is should be able to run as a * separate process, playing Angband in a window just like a human, that * is, examining the screen for information, and sending keypresses to * the game. The current Borg does not actually do this, because it would * be very slow and would not run except on Unix machines, but as far as * possible, I have attempted to make sure that the Borg *could* run that * way. This involves "cheating" as little as possible, where "cheating" * means accessing information not available to a normal Angband player. * And whenever possible, this "cheating" should be optional, that is, * there should be software options to disable the cheating, and, if * necessary, to replace it with "complex" parsing of the screen. * * Thus, the Borg COULD be written as a separate process which runs Angband * in a pseudo-terminal and "examines" the "screen" and sends keypresses * directly (as with a terminal emulator), although it would then have * to explicitly "wait" to make sure that the game was completely done * sending information. * * The Borg is thus allowed to examine the screen directly (by efficient * direct access of the "Term->scr->a" and "Term->scr->c" arrays, which * could be replaced by calls to "Term_grab()"), and to access the cursor * location (via "Term_locate()") and visibility (via "Term_get_cursor()"), * and, as mentioned above, the Borg is allowed to send keypresses directly * to the game, and only when needed, using the "Term_inkey_hook" hook, and * uses the same hook to know when it should discard all pending keypresses. * * The Borg should not know when the game is ready for a keypress, and * should really do something nasty such as "pause" between turns for * some amount of time to ensure that the game is really waiting for * a keypress. * * Various other "cheats" (mostly optional) are described where they are * used, primarily in this file. * * Note that any "user input" will be ignored, and will cancel the Borg, * after the Borg has completed any key-sequences currently in progress. * * Note that the "c_t" parameter bears a close resemblance to the number of * "player turns" that have gone by. Except that occasionally, the Borg will * do something that he *thinks* will take time but which actually does not * (for example, attempting to open a hallucinatory door), and that sometimes, * the Borg performs a "repeated" command (rest, open, tunnel, or search), * which may actually take longer than a single turn. This has the effect * that the "c_t" variable is slightly lacking in "precision". Note that * we can store every time-stamp in a 's16b', since we reset the clock to * 1000 on each new level, and we refuse to stay on any level longer than * 30000 turns, unless we are totally stuck, in which case we abort. * * Note that as of 2.7.9, the Borg can play any class, that is, he can make * "effective" use of at least a few spells/prayers, and is not "broken" * by low strength, blind-ness, hallucination, etc. This does not, however, * mean that he plays all classes equally well, especially since he is so * dependant on a high strength for so many things. The "demo" mode is useful * for many classes (especially Mage) since it allows the Borg to "die" a few * times, without being penalized. * * The Borg assumes that the "maximize" flag is off, and that the * "preserve" flag is on, since he cannot actually set those flags. * If the "maximize" flag is on, the Borg may not work correctly. * If the "preserve" flag is off, the Borg may miss artifacts. */ /* * We currently handle: * Level changing (intentionally or accidentally) * Embedded objects (gold) that must be extracted * Ignore embedded objects if too "weak" to extract * Traps (disarm), Doors (open/etc), Rubble (tunnel) * Stores (enter via movement, exit via escape) * Stores (limited commands, and different commands) * Always deal with objects one at a time, not in piles * Discard junk before trying to pick up more stuff * Use "identify" to obtain knowledge and/or money * Rely on "sensing" objects as much as possible * Do not sell junk or worthless items to any shop * Do not attempt to buy something without the cash * Use the non-optimal stairs if stuck on a level * Use "flow" code for all tasks for consistency * Cancel all goals when major world changes occur * Use the "danger" code to avoid potential death * Use the "danger" code to avoid inconvenience * Try to avoid danger (both actively and passively) * Handle "Mace of Disruption", "Scythe of Slicing", etc * Learn spells, and use them when appropriate * Remember that studying prayers is slightly random * Do not try to read scrolls when blind or confused * Do not study/use spells/prayers when blind/confused * Use spells/prayers at least once for the experience * Attempt to heal when "confused", "blind", etc * Attempt to fix "fear", "poison", "cuts", etc * Analyze potential equipment in proper context * Priests should avoid edged weapons (spell failure) * Mages should avoid most gloves (lose mana) * Non-warriors should avoid heavy armor (lose mana) * Keep "best" ring on "tight" right finger in stores * Remove items which do not contribute to total fitness * Wear/Remove/Sell/Buy items in most optimal order * Pursue optimal combination of available equipment * Notice "failure" when using rods/staffs/artifacts * Notice "failure" when attempting spells/prayers * Attempt to correctly track terrain, objects, monsters * Take account of "clear" and "multi-hued" monsters * Take account of "flavored" (randomly colored) objects * Handle similar objects/monsters (mushrooms, coins) * Multi-hued/Clear monsters, and flavored objects * Keep in mind that some monsters can move (quickly) * Do not fire at monsters that may not actually exist * Assume everything is an object until proven otherwise * Parse messages to correct incorrect assumptions * Search for secret doors after exploring the level * React intelligently to changes in the wall structure * Do not recalculate "flow" information unless required * Collect monsters/objects/terrain not currently in view * Keep in mind that word of recall is a delayed action * Keep track of charging items (rods and artifacts) * Be very careful not to access illegal locations! * Do not rest next to dangerous (or immobile) monsters * Recall into dungeon if prepared for resulting depth * Do not attempt to destroy cursed ("terrible") artifacts * Attempted destruction will yield "terrible" inscription * Use "maximum" level and depth to prevent "thrashing" * Use "maximum" hp's and sp's when checking "potentials" * Attempt to recognize large groups of "disguised" monsters * Beware of firing at a monster which is no longer present * Stockpile items in the Home, and use those stockpiles * Discounted spell-books (low level ones are ignored) * Take items out of the home to sell them when no longer needed * Trappers and Mimics (now treated as invisible monsters) * Invisible monsters (induce "fear" of nearby regions) * Fleeing monsters are "followed" down corridors and such * * We ignore: * Running out of light can (fatally) confuse the Borg * Running out of food can kill you, try not to starve * Long object descriptions may have clipped inscriptions * * We need to handle: * Better "fleeing" code from nasty monsters * Appearance of "similar" monsters (jackals + grip) * Hallucination (induces fake objects and monsters) * Special screens (including tombstone) with no "walls" * Appearance of the '@' symbol on "special" screens * Technically a room can have no exits, requiring digging * Try to use a shovel/pick to help with tunnelling * If wounded, must run away from monsters, then rest * When blind, monster and object info may be invalid * When totally surrounded by monsters, try to escape rooms * Conserve memory space (each grid byte costs about 15K) * Conserve computation time (especially with the flow code) * Note -- nutrition can come from food, scrolls, or spells * Note -- recall can come from scrolls, rods, or spells * Note -- identify can come from scrolls, rods, staffs, or spells * Becoming "afraid" (attacking takes a turn for no effect) * Beware of firing missiles at a food ration under a mushroom * Attempt to save possibly useful equipment in the home * * We need to handle "loading" saved games: * The "max_depth" value is lost if loaded in the town * If we track "dead uniques" then this information is lost * The "map" info, "flow" info, "tracking" info, etc is lost * The contents of the shops (and the home) are lost * We may be asked to "resume" a non-Borg character (icky) */ /* * Currently, the Borg "cheats" in a few situations... * * Cheats that are significant, and possibly unavoidable: * Knowledge of when we are being asked for a keypress. * Note that this could be avoided by LONG timeouts/delays * * Cheats "required" by implementation, but not signifant: * Direct access to the "screen image" (parsing screen) * Direct access to the "keypress queue" (sending keys) * Direct access to the "cursor visibility" (game state) * * Cheats that could be avoided by simple (ugly) code: * Direct modification of the "current options" * * Cheats that could be avoided by duplicating code: * Use of the tables in "tables.c" * Use of the arrays initialized in "init.c" * * Cheats that can be avoided by toggling a switch: * Direct extraction of "panel" info (auto_cheat_panel) * Direct extraction of "inven" info (auto_cheat_inven) * Direct extraction of "equip" info (auto_cheat_equip) * Direct extraction of "spell" info (auto_cheat_spell) * * Cheats that the Borg would love: * Immunity to hallucination, blindness, confusion * Unique attr/char codes for every monster and object * Removal of the "mimic" and "trapper" monsters * Removal of the "mushroom" and "gold" monsters */ /* * Stat advantages: * High STR (attacks, to-dam, digging, weight limit) * High DEX (attacks, to-hit, armor class) * High CON (hitpoints, recovery) * High WIS (better prayers, saving throws) * High INT (better spells, disarming, device usage) * High CHR (better item costs) * * Class advantages: * Warrior (good fighting, sensing) * Mage (good spells) * Priest (good prayers, fighting) * Ranger (some spells, fighting) * Rogue (some spells, fighting, sensing) * Paladin (prayers, fighting, sensing) * * Race advantages: * Gnome (free action) * Dwarf (resist blindness) * High elf (see invisible) * Non-human (infravision) */ /* * Some variables */ static bool initialized; /* Hack -- Initialized */ /* * Mega-Hack -- extract some "hidden" variables * * XXX XXX XXX This step would not be necessary if more info * was available on the screen. * */ static void borg_hidden(void) { int i; /* Clear the stat modifiers */ for (i = 0; i < 6; i++) my_stat_add[i] = 0; /* Scan the usable inventory */ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* if we have on unidentified stuff we may have misguessed our */ /* stats. */ if (!item->able) { my_need_stat_check[0] = TRUE; my_need_stat_check[1] = TRUE; my_need_stat_check[2] = TRUE; my_need_stat_check[3] = TRUE; my_need_stat_check[4] = TRUE; my_need_stat_check[5] = TRUE; break; } /* Affect stats */ if (item->flags1 & TR1_STR) my_stat_add[A_STR] += item->pval; if (item->flags1 & TR1_INT) my_stat_add[A_INT] += item->pval; if (item->flags1 & TR1_WIS) my_stat_add[A_WIS] += item->pval; if (item->flags1 & TR1_DEX) my_stat_add[A_DEX] += item->pval; if (item->flags1 & TR1_CON) my_stat_add[A_CON] += item->pval; if (item->flags1 & TR1_CHR) my_stat_add[A_CHR] += item->pval; } /* Mega-Hack -- Guess at "my_stat_cur[]" */ for (i = 0; i < 6; i++) { int value; if (!my_need_stat_check[i]) continue; /* Reverse known bonuses to get the base stat value */ value = modify_stat_value(auto_stat[i], -my_stat_add[i]); /* If the displayed stat is 18/220 this was just a guess. */ /* The player still needs to take off some stuff to get the */ /* real value. */ if (auto_stat[i] < 238) { my_need_stat_check[i] = FALSE; } /* Hack -- save the maximum/current stats */ my_stat_cur[i] = value; /* Max stat is the max that the cur stat ever is. */ if (my_stat_cur[i] > my_stat_max[i]) my_stat_max[i] = my_stat_cur[i]; /* if this stat is not in need of fixing and */ /* it is less than the max it should be equal to the max */ /* and we are done. */ #if 0 /* there is a problem with this when you get drained but are above */ /* 18/220 and after you forget your stuff */ if (my_need_stat_check[i] && !do_fix_stat[i] && my_stat_max[i] > my_stat_cur[i]) { my_stat_cur[i] = my_stat_max[i]; my_need_stat_check[i] = FALSE; } #endif } } /* * Think about the world and perform an action * * Check inventory/equipment/spells/panel once per "turn" * * Process "store" and other modes when necessary * * Note that the non-cheating "inventory" and "equipment" parsers * will get confused by a "weird" situation involving an ant ("a") * on line one of the screen, near the left, next to a shield, of * the same color, and using --(-- the ")" symbol, directly to the * right of the ant. This is very rare, but perhaps not completely * impossible. I ignore this situation. :-) * * The handling of stores is a complete and total hack, but seems * to work remarkably well, considering... :-) Note that while in * a store, time does not pass, and most actions are not available, * and a few new commands are available ("sell" and "purchase"). * * Note the use of "cheat" functions to extract the current inventory, * the current equipment, the current panel, and the current spellbook * information. These can be replaced by (very expensive) "parse" * functions, which cause an insane amount of "screen flashing". * * Technically, we should attempt to parse all the messages that * indicate that it is necessary to re-parse the equipment, the * inventory, or the books, and only set the appropriate flags * at that point. This would not only reduce the potential * screen flashing, but would also optimize the code a lot, * since the "cheat_inven()" and "cheat_equip()" functions * are expensive. For paranoia, we could always select items * and spells using capital letters, and keep a global verification * buffer, and induce failure and recheck the inventory/equipment * any time we get a mis-match. We could even do some of the state * processing by hand, for example, charge reduction and such. This * might also allow us to keep track of how long we have held objects, * especially if we attempt to do "item tracking" in the inventory * extraction code. */ static bool borg_think(void) { int i; byte t_a; char buf[128]; /*** Process inventory/equipment ***/ /* Cheat */ if (auto_cheat_equip && auto_do_equip) { /* Only do it once */ auto_do_equip = FALSE; /* Cheat the "equip" screen */ borg_cheat_equip(); /* Done */ return (FALSE); } /* Cheat */ if (auto_cheat_inven && auto_do_inven) { /* Only do it once */ auto_do_inven = FALSE; /* Cheat the "inven" screen */ borg_cheat_inven(); /* Done */ return (FALSE); } /* save now */ if (borg_save && borg_save_game()) { /* Log */ borg_note("# Auto Save!"); borg_save = FALSE; return (TRUE); } /* Parse "equip" mode */ if ((0 == borg_what_text(0, 0, 10, &t_a, buf)) && (streq(buf, "Equipment "))) { /* Parse the "equip" screen */ borg_parse_equip(); /* Leave this mode */ borg_keypress(ESCAPE); /* Done */ return (TRUE); } /* Parse "inven" mode */ if ((0 == borg_what_text(0, 0, 10, &t_a, buf)) && (streq(buf, "Inventory "))) { /* Parse the "inven" screen */ borg_parse_inven(); /* Leave this mode */ borg_keypress(ESCAPE); /* Done */ return (TRUE); } /* Check "equip" */ if (auto_do_equip) { /* Only do it once */ auto_do_equip = FALSE; /* Enter "equip" mode */ borg_keypress('e'); /* Done */ return (TRUE); } /* Check "inven" */ if (auto_do_inven) { /* Only do it once */ auto_do_inven = FALSE; /* Enter "inven" mode */ borg_keypress('i'); /* Done */ return (TRUE); } /*** Find books ***/ /* Only if needed */ if (auto_do_spell && (auto_do_spell_aux == 0)) { /* Assume no books */ for (i = 0; i < 9; i++) auto_book[i] = -1; /* Scan the pack */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip non-books */ if (item->tval != mb_ptr->spell_book) continue; /* Note book locations */ auto_book[item->sval] = i; } } /*** Process books ***/ /* Hack -- Warriors never browse */ if (auto_class == 0) auto_do_spell = FALSE; /* Hack -- Blind or Confused prevents browsing */ if (do_blind || do_confused) auto_do_spell = FALSE; /* XXX XXX XXX Dark */ /* Hack -- Stop doing spells when done */ if (auto_do_spell_aux > 8) auto_do_spell = FALSE; /* Cheat */ if (auto_cheat_spell && auto_do_spell) { /* Look for the book */ i = auto_book[auto_do_spell_aux]; /* Cheat the "spell" screens (all of them) */ if (i >= 0) { /* Cheat that page */ borg_cheat_spell(auto_do_spell_aux); } /* Advance to the next book */ auto_do_spell_aux++; /* Done */ return (FALSE); } /* Check for "browse" mode */ if ((0 == borg_what_text(COL_SPELL, ROW_SPELL, -12, &t_a, buf)) && (streq(buf, "Lv Mana Fail"))) { /* Parse the "spell" screen */ borg_parse_spell(auto_do_spell_aux); /* Advance to the next book */ auto_do_spell_aux++; /* Leave that mode */ borg_keypress(ESCAPE); /* Done */ return (TRUE); } /* Check "spells" */ if (auto_do_spell) { /* Look for the book */ i = auto_book[auto_do_spell_aux]; /* Enter the "spell" screen */ if (i >= 0) { /* Enter "browse" mode */ borg_keypress('b'); /* Pick the next book */ borg_keypress(I2A(i)); /* Done */ return (TRUE); } /* Advance to the next book */ auto_do_spell_aux++; /* Done */ return (FALSE); } /* check for anything that needs *ID* */ if ( auto_do_star_id ) { if (borg_object_star_id()) return (TRUE); auto_do_star_id = FALSE; } /* if king and in town, retire. Let the player do this. */ if (borg_king && !auto_depth) { borg_oops("retire"); } /*** Handle stores ***/ /* Hack -- Check for being in a store */ if ((0 == borg_what_text(3, 5, 16, &t_a, buf)) && (streq(buf, "Item Description"))) { /* Assume the Home */ shop_num = 7; /* Extract the "store" name */ if (0 == borg_what_text(50, 3, -20, &t_a, buf)) { int i; /* Check the store names */ for (i = 0; i < 7; i++) { cptr name = (f_name + f_info[0x08+i].name); if (prefix(buf, name)) shop_num = i; } } /* Hack -- reset page/more */ auto_shops[shop_num].page = 0; auto_shops[shop_num].more = 0; /* React to new stores */ if (auto_do_browse_what != shop_num) { /* Clear all the items */ for (i = 0; i < 24; i++) { /* XXX Wipe the ware */ WIPE(&auto_shops[shop_num].ware[i], auto_item); } /* Save the store */ auto_do_browse_what = shop_num; } /* Extract the "page", if any */ if ((0 == borg_what_text(20, 5, 8, &t_a, buf)) && (prefix(buf, "(Page "))) /* --)-- */ { /* Take note of the page */ auto_shops[shop_num].more = 1; auto_shops[shop_num].page = (buf[6] - '0') - 1; } /* React to disappearing pages */ if (auto_do_browse_more != auto_shops[shop_num].more) { /* Clear the second page */ for (i = 12; i < 24; i++) { /* XXX Wipe the ware */ WIPE(&auto_shops[shop_num].ware[i], auto_item); } /* Save the new one */ auto_do_browse_more = auto_shops[shop_num].more; auto_do_browse = auto_do_browse_more; } /* Extract the current gold (unless in home) */ if (0 == borg_what_text(68, 19, -9, &t_a, buf)) { /* Save the gold, if valid */ if (buf[0]) auto_gold = atol(buf); } /* Parse the store (or home) inventory */ for (i = 0; i < 12; i++) { int n; char desc[80]; char cost[10]; /* Default to "empty" */ desc[0] = '\0'; cost[0] = '\0'; /* Verify "intro" to the item */ if ((0 == borg_what_text(0, i + 6, 3, &t_a, buf)) && (buf[0] == I2A(i)) && (buf[1] == p2) && (buf[2] == ' ')) { int k; /* Extract the item description */ if (0 != borg_what_text(3, i + 6, -65, &t_a, desc)) { desc[0] = '\0'; } /* Strip trailing spaces */ for (k = strlen(desc); (k > 0) && (desc[k-1] == ' '); k--) /* loop */; desc[k] = '\0'; /* Extract the item cost in stores */ if (shop_num != 7) { if (0 != borg_what_text(68, i + 6, -9, &t_a, cost)) { cost[0] = '\0'; } } } /* Extract actual index */ n = auto_shops[shop_num].page * 12 + i; /* Ignore "unchanged" descriptions */ if (streq(desc, auto_shops[shop_num].ware[n].desc)) continue; /* Analyze the item */ borg_item_analyze(&auto_shops[shop_num].ware[n], desc); /*need to be able to analize the home inventory to see if it was */ /* *fully ID*d. */ /* This is a BIG CHEAT! It will be less of a cheat if code is put*/ /* in place to allow 'I' in stores. */ #ifdef ID_MENTAL if (store[shop_num].stock[n].ident & ID_MENTAL) { /* XXX XXX XXX for now, allways cheat to get info on items at */ /* home. */ borg_object_star_id_aux( &auto_shops[shop_num].ware[n], &store[shop_num].stock[n]); auto_shops[shop_num].ware[n].fully_identified = TRUE; } #endif /* Hack -- Save the declared cost */ auto_shops[shop_num].ware[n].cost = atol(cost); } /* Hack -- browse as needed */ if (auto_shops[shop_num].more && auto_do_browse) { /* Check next page */ borg_keypress(' '); /* Done browsing */ auto_do_browse = FALSE; /* Done */ return (TRUE); } /* Recheck inventory */ auto_do_inven = TRUE; /* Recheck equipment */ auto_do_equip = TRUE; /* Recheck spells */ auto_do_spell = TRUE; /* Restart spells */ auto_do_spell_aux = 0; /* Hack -- browse again later */ auto_do_browse = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the current world */ my_power = borg_power(); /* Hack -- allow user abort */ if (auto_cancel) return (TRUE); /* Think until done */ return (borg_think_store()); } /*** Determine panel ***/ /* Hack -- cheat */ if (auto_cheat_panel) { /* Cheat */ w_y = panel_row * (SCREEN_HGT / 2); w_x = panel_col * (SCREEN_WID / 2); /* Done */ auto_do_panel = FALSE; } /* Hack -- Check for "sector" mode */ if ((0 == borg_what_text(0, 0, 16, &t_a, buf)) && (prefix(buf, "Map sector "))) { /* Hack -- get the panel info */ w_y = (buf[12] - '0') * (SCREEN_HGT / 2); w_x = (buf[14] - '0') * (SCREEN_WID / 2); /* Leave panel mode */ borg_keypress(ESCAPE); /* Done */ return (TRUE); } /* Check equipment */ if (auto_do_panel) { /* Only do it once */ auto_do_panel = FALSE; /* Enter "panel" mode */ borg_keypress('L'); /* Done */ return (TRUE); } /*** Analyze the Frame ***/ /* Analyze the frame */ if (auto_do_frame) { /* Only once */ auto_do_frame = FALSE; /* Analyze the "frame" */ borg_update_frame(); } /*** Re-activate Tests ***/ /* Check equip again later */ auto_do_equip = TRUE; /* Check inven again later */ auto_do_inven = TRUE; /* Check panel again later */ auto_do_panel = TRUE; /* Check frame again later */ auto_do_frame = TRUE; /* Check spells again later */ auto_do_spell = TRUE; /* Hack -- Start the books over */ auto_do_spell_aux = 0; /*** Analyze status ***/ /* Track best level */ if (auto_level > auto_max_level) auto_max_level = auto_level; if (auto_depth > auto_max_depth) { auto_max_depth = auto_depth; finished_level = FALSE; } /*** Think about it ***/ /* Increment the clock */ c_t++; /* Examine the screen */ borg_update(); /* Extract some "hidden" variables */ borg_hidden(); /* Examine the equipment/inventory */ borg_notice(); /* Evaluate the current world */ my_power = borg_power(); /* Hack -- allow user abort */ if (auto_cancel) return (TRUE); /* Do something */ return (borg_think_dungeon()); } /* * Hack -- methods of hurting a monster (order not important). * * See "message_pain()" for details. */ static cptr suffix_pain[] = { " barely notices.", " flinches.", " squelches.", " quivers in pain.", " writhes about.", " writhes in agony.", " jerks limply.", " shrugs off the attack.", " snarls with pain.", " yelps in pain.", " howls in pain.", " howls in agony.", /* xxx */ " yelps feebly.", " ignores the attack.", " grunts with pain.", " squeals in pain.", " shrieks in pain.", " shrieks in agony.", /* xxx */ " cries out feebly.", /* xxx */ /* xxx */ " cries out in pain.", " screams in pain.", " screams in agony.", /* xxx */ /* xxx */ NULL }; /* * Hack -- methods of killing a monster (order not important). * * See "mon_take_hit()" for details. */ static cptr prefix_kill[] = { "You have killed ", "You have slain ", "You have destroyed ", NULL }; /* * Hack -- methods of monster death (order not important). * * See "project_m()", "do_cmd_fire()", "mon_take_hit()" for details. */ static cptr suffix_died[] = { " dies.", " is destroyed.", " dissolves!", " shrivels away in the light!", NULL }; /* * Hack -- methods of hitting the player (order not important). * * The "insult", "moan", and "begs you for money" messages are ignored. * * See "make_attack_normal()" for details. */ static cptr suffix_hit_by[] = { " hits you.", " touches you.", " punches you.", " kicks you.", " claws you.", " bites you.", " stings you.", " butts you.", " crushes you.", " engulfs you.", " crawls on you.", " drools on you.", " spits on you.", " gazes at you.", " wails at you.", " releases spores at you.", NULL }; /* * Hack -- methods of casting spells at the player (order important). * * See "make_attack_spell()" for details. */ static cptr suffix_spell[] = { " makes a high pitched shriek.", /* RF4_SHRIEK */ " does something.", /* RF4_XXX2X4 */ " does something.", /* RF4_XXX3X4 */ " does something.", /* RF4_XXX4X4 */ " fires an arrow.", /* RF4_ARROW_1 */ " fires an arrow!", /* RF4_ARROW_2 */ " fires a missile.", /* RF4_ARROW_3 */ " fires a missile!", /* RF4_ARROW_4 */ " breathes acid.", /* RF4_BR_ACID */ " breathes lightning.", /* RF4_BR_ELEC */ " breathes fire.", /* RF4_BR_FIRE */ " breathes frost.", /* RF4_BR_COLD */ " breathes gas.", /* RF4_BR_POIS */ " breathes nether.", /* RF4_BR_NETH */ " breathes light.", /* RF4_BR_LITE */ " breathes darkness.", /* RF4_BR_DARK */ " breathes confusion.", /* RF4_BR_CONF */ " breathes sound.", /* RF4_BR_SOUN */ " breathes chaos.", /* RF4_BR_CHAO */ " breathes disenchantment.", /* RF4_BR_DISE */ " breathes nexus.", /* RF4_BR_NEXU */ " breathes time.", /* RF4_BR_TIME */ " breathes inertia.", /* RF4_BR_INER */ " breathes gravity.", /* RF4_BR_GRAV */ " breathes shards.", /* RF4_BR_SHAR */ " breathes plasma.", /* RF4_BR_PLAS */ " breathes force.", /* RF4_BR_WALL */ " does something.", /* RF4_BR_MANA */ " does something.", /* RF4_XXX5X4 */ " does something.", /* RF4_XXX6X4 */ " does something.", /* RF4_XXX7X4 */ " does something.", /* RF4_XXX8X4 */ " casts an acid ball.", /* RF5_BA_ACID */ " casts a lightning ball.", /* RF5_BA_ELEC */ " casts a fire ball.", /* RF5_BA_FIRE */ " casts a frost ball.", /* RF5_BA_COLD */ " casts a stinking cloud.", /* RF5_BA_POIS */ " casts a nether ball.", /* RF5_BA_NETH */ " gestures fluidly.", /* RF5_BA_WATE */ " invokes a mana storm.", /* RF5_BA_MANA */ " invokes a darkness storm.", /* RF5_BA_DARK */ " draws psychic energy from you!", /* RF5_DRAIN_MANA */ " gazes deep into your eyes.", /* RF5_MIND_BLAST */ " looks deep into your eyes.", /* RF5_BRAIN_SMASH */ " points at you and curses.", /* RF5_CAUSE_1 */ " points at you and curses horribly.", /* RF5_CAUSE_2 */ " points at you, incanting terribly!", /* RF5_CAUSE_3 */ " points at you, screaming the word DIE!", /* RF5_CAUSE_4 */ " casts a acid bolt.", /* RF5_BO_ACID */ " casts a lightning bolt.", /* RF5_BO_ELEC */ " casts a fire bolt.", /* RF5_BO_FIRE */ " casts a frost bolt.", /* RF5_BO_COLD */ " does something.", /* RF5_BO_POIS */ " casts a nether bolt.", /* RF5_BO_NETH */ " casts a water bolt.", /* RF5_BO_WATE */ " casts a mana bolt.", /* RF5_BO_MANA */ " casts a plasma bolt.", /* RF5_BO_PLAS */ " casts an ice bolt.", /* RF5_BO_ICEE */ " casts a magic missile.", /* RF5_MISSILE */ " casts a fearful illusion.", /* RF5_SCARE */ " casts a spell, burning your eyes!", /* RF5_BLIND */ " creates a mesmerising illusion.", /* RF5_CONF */ " drains power from your muscles!", /* RF5_SLOW */ " stares deep into your eyes!", /* RF5_HOLD */ " concentrates on XXX body.", /* RF6_HASTE */ " does something.", /* RF6_XXX1X6 */ " concentrates on XXX wounds.", /* RF6_HEAL */ " does something.", /* RF6_XXX2X6 */ " blinks away.", /* RF6_BLINK */ " teleports away.", /* RF6_TPORT */ " does something.", /* RF6_XXX3X6 */ " does something.", /* RF6_XXX4X6 */ " commands you to return.", /* RF6_TELE_TO */ " teleports you away.", /* RF6_TELE_AWAY */ " gestures at your feet.", /* RF6_TELE_LEVEL */ " does something.", /* RF6_XXX5 */ " gestures in shadow.", /* RF6_DARKNESS */ " casts a spell and cackles evilly.", /* RF6_TRAPS */ " tries to blank your mind.", /* RF6_FORGET */ " does something.", /* RF6_XXX6X6 */ " does something.", /* RF6_XXX7X6 */ " does something.", /* RF6_XXX8X6 */ " magically summons help!", /* RF6_S_MONSTER */ " magically summons monsters!", /* RF6_S_MONSTERS */ " magically summons ants.", /* RF6_S_ANT */ " magically summons spiders.", /* RF6_S_SPIDER */ " magically summons hounds.", /* RF6_S_HOUND */ " magically summons hydras.", /* RF6_S_HYDRA */ " magically summons an angel!", /* RF6_S_ANGEL */ " magically summons a hellish adversary!", /* RF6_S_DEMON */ " magically summons an undead adversary!", /* RF6_S_UNDEAD */ " magically summons a dragon!", /* RF6_S_DRAGON */ " magically summons greater undead!", /* RF6_S_HI_UNDEAD */ " magically summons ancient dragons!", /* RF6_S_HI_DRAGON */ " magically summons mighty undead opponents!", /* RF6_S_WRAITH */ " magically summons special opponents!", /* RF6_S_UNIQUE */ NULL }; #if 0 /* XXX XXX XXX */ msg_format("%^s looks healthier.", m_name); msg_format("%^s looks REALLY healthy!", m_name); #endif /* * Hack -- Spontaneous level feelings (order important). * * See "do_cmd_feeling()" for details. */ static cptr prefix_feeling[] = { "Looks like any other level", "You feel there is something special", "You have a superb feeling", "You have an excellent feeling", "You have a very good feeling", "You have a good feeling", "You feel strangely lucky", "You feel your luck is turning", "You like the look of this place", "This level can't be all bad", "What a boring place", NULL }; /* * Hack -- Parse a message from the world * * Note that detecting "death" is EXTREMELY important, to prevent * all sorts of errors arising from attempting to parse the "tomb" * screen, and to allow the user to "observe" the "cause" of death. * * Note that detecting "failure" is EXTREMELY important, to prevent * bizarre situations after failing to use a staff of perceptions, * which would otherwise go ahead and send the "item index" which * might be a legal command (such as "a" for "aim"). This method * is necessary because the Borg cannot parse "prompts", and must * assume the success of the prompt-inducing command, unless told * otherwise by a failure message. Also, we need to detect failure * because some commands, such as detection spells, need to induce * furthur processing if they succeed, but messages are only given * if the command fails. * * Note that certain other messages may contain useful information, * and so they are "analyzed" and sent to "borg_react()", which just * queues the messages for later analysis in the proper context. * * Along with the actual message, we send a special formatted buffer, * containing a leading "opcode", which may contain extra information, * such as the index of a spell, and an "argument" (for example, the * capitalized name of a monster), with a "colon" to separate them. * * XXX XXX XXX Several message strings take a "possessive" of the form * "his" or "her" or "its". These strings are all represented by the * encoded form "XXX" in the various match strings. Unfortunately, * the encode form is never decoded, so the Borg currently ignores * messages about several spells (heal self and haste self). * * XXX XXX XXX We notice a few "terrain feature" messages here so * we can acquire knowledge about wall types and door types. */ static void borg_parse_aux(cptr msg, int len) { int i, tmp; char who[256]; char buf[256]; auto_grid *ag = &auto_grids[g_y][g_x]; /* Log (if needed) */ if (auto_fff) borg_info(format("& Msg <%s>", msg)); /* Hack -- Notice death */ if (prefix(msg, "You die.")) { /* Abort (unless cheating) */ if (!(wizard || cheat_live)) { /* Abort */ borg_oops("death"); /* Abort right now! */ auto_active = FALSE; /* Noise XXX XXX XXX */ Term_xtra(TERM_XTRA_NOISE, 1); } /* Done */ return; } /* Hack -- Notice "failure" */ if (prefix(msg, "You failed ")) { /* Hack -- store the keypress */ borg_note("# Normal failure."); /* Set the failure flag */ auto_failure = TRUE; /* Flush our key-buffer */ borg_flush(); return; } /* Ignore teleport trap */ if (prefix(msg, "You hit a teleport")) return; /* Ignore arrow traps */ if (prefix(msg, "An arrow ")) return; /* Ignore dart traps */ if (prefix(msg, "A small dart ")) return; if (prefix(msg, "The cave ")) { borg_react(msg, "QUAKE"); return; } /* need to check stat */ if (prefix(msg, "You feel very") || prefix(msg, "You feel less") || prefix(msg, "Wow! You feel very")) { /* need to check str */ if (prefix(msg, "You feel very weak")) { my_need_stat_check[0] = TRUE; } if (prefix(msg, "You feel less weak")) { my_need_stat_check[0] = TRUE; } if (prefix(msg, "Wow! You feel very strong")) { my_need_stat_check[0] = TRUE; } /* need to check int */ if (prefix(msg, "You feel very stupid")) { my_need_stat_check[1] = TRUE; } if (prefix(msg, "You feel less stupid")) { my_need_stat_check[1] = TRUE; } if (prefix(msg, "Wow! You feel very smart")) { my_need_stat_check[1] = TRUE; } /* need to check wis */ if (prefix(msg, "You feel very naive")) { my_need_stat_check[2] = TRUE; } if (prefix(msg, "You feel less naive")) { my_need_stat_check[2] = TRUE; } if (prefix(msg, "Wow! You feel very wise")) { my_need_stat_check[2] = TRUE; } /* need to check dex */ if (prefix(msg, "You feel very clumsy")) { my_need_stat_check[3] = TRUE; } if (prefix(msg, "You feel less clumsy")) { my_need_stat_check[3] = TRUE; } if (prefix(msg, "Wow! You feel very dextrous")) { my_need_stat_check[3] = TRUE; } /* need to check con */ if (prefix(msg, "You feel very sickly")) { my_need_stat_check[4] = TRUE; } if (prefix(msg, "You feel less sickly")) { my_need_stat_check[4] = TRUE; } if (prefix(msg, "Wow! You feel very healthy")) { my_need_stat_check[4] = TRUE; } /* need to check cha */ if (prefix(msg, "You feel very ugly")) { my_need_stat_check[5] = TRUE; } if (prefix(msg, "You feel less ugly")) { my_need_stat_check[5] = TRUE; } if (prefix(msg, "Wow! You feel very cute")) { my_need_stat_check[5] = TRUE; } } /* time attacks, just do all stats. */ if (prefix(msg, "You're not as")) { my_need_stat_check[0] = TRUE; my_need_stat_check[1] = TRUE; my_need_stat_check[2] = TRUE; my_need_stat_check[3] = TRUE; my_need_stat_check[4] = TRUE; my_need_stat_check[5] = TRUE; } /* Nexus attacks, need to check everything! */ if (prefix(msg, "Your body starts to scramble...")) { my_need_stat_check[0] = TRUE; my_need_stat_check[1] = TRUE; my_need_stat_check[2] = TRUE; my_need_stat_check[3] = TRUE; my_need_stat_check[4] = TRUE; my_need_stat_check[5] = TRUE; /* max stats may have lowered */ my_stat_max[0] = 0; my_stat_max[1] = 0; my_stat_max[2] = 0; my_stat_max[3] = 0; my_stat_max[4] = 0; my_stat_max[5] = 0; } /* Hit somebody */ if (prefix(msg, "You hit ")) { tmp = strlen("You hit "); strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp); strnfmt(buf, 256, "HIT:%^s", who); borg_react(msg, buf); return; } /* Miss somebody */ if (prefix(msg, "You miss ")) { tmp = strlen("You miss "); strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp); strnfmt(buf, 256, "MISS:%^s", who); borg_react(msg, buf); return; } /* Miss somebody (because of fear) */ if (prefix(msg, "You are too afraid to attack ")) { tmp = strlen("You are too afraid to attack "); strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp); strnfmt(buf, 256, "MISS:%^s", who); borg_react(msg, buf); return; } /* "It screams in pain." (etc) */ for (i = 0; suffix_pain[i]; i++) { /* "It screams in pain." (etc) */ if (suffix(msg, suffix_pain[i])) { tmp = strlen(suffix_pain[i]); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "PAIN:%^s", who); borg_react(msg, buf); return; } } /* "You have killed it." (etc) */ for (i = 0; prefix_kill[i]; i++) { /* "You have killed it." (etc) */ if (prefix(msg, prefix_kill[i])) { tmp = strlen(prefix_kill[i]); strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp); strnfmt(buf, 256, "KILL:%^s", who); borg_react(msg, buf); return; } } /* "It dies." (etc) */ for (i = 0; suffix_died[i]; i++) { /* "It dies." (etc) */ if (suffix(msg, suffix_died[i])) { tmp = strlen(suffix_died[i]); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "DIED:%^s", who); borg_react(msg, buf); return; } } /* "It misses you." */ if (suffix(msg, " misses you.")) { tmp = strlen(" misses you."); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "MISS_BY:%^s", who); borg_react(msg, buf); return; } /* "It is repelled.." */ /* treat as a miss */ if (suffix(msg, " is repelled.")) { tmp = strlen(" is repelled."); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "MISS_BY:%^s", who); borg_react(msg, buf); return; } /* "It hits you." (etc) */ for (i = 0; suffix_hit_by[i]; i++) { /* "It hits you." (etc) */ if (suffix(msg, suffix_hit_by[i])) { tmp = strlen(suffix_hit_by[i]); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "HIT_BY:%^s", who); borg_react(msg, buf); return; } } /* "It casts a spell." (etc) */ for (i = 0; suffix_spell[i]; i++) { /* "It casts a spell." (etc) */ if (suffix(msg, suffix_spell[i])) { tmp = strlen(suffix_spell[i]); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "SPELL_%03d:%^s", 96+i, who); borg_react(msg, buf); return; } } /* State -- Asleep */ if (suffix(msg, " falls asleep!")) { tmp = strlen(" falls asleep!"); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "STATE_SLEEP:%^s", who); borg_react(msg, buf); return; } /* State -- Not Asleep */ if (suffix(msg, " wakes up.")) { tmp = strlen(" wakes up."); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "STATE_AWAKE:%^s", who); borg_react(msg, buf); return; } /* State -- Afraid */ if (suffix(msg, " flees in terror!")) { tmp = strlen(" flees in terror!"); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "STATE__FEAR:%^s", who); borg_react(msg, buf); return; } /* State -- Not Afraid */ if (suffix(msg, " recovers his courage.")) { tmp = strlen(" recovers his courage."); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "STATE__BOLD:%^s", who); borg_react(msg, buf); return; } /* State -- Not Afraid */ if (suffix(msg, " recovers her courage.")) { tmp = strlen(" recovers her courage."); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "STATE__BOLD:%^s", who); borg_react(msg, buf); return; } /* State -- Not Afraid */ if (suffix(msg, " recovers its courage.")) { tmp = strlen(" recovers its courage."); strnfmt(who, 1 + len - tmp, "%s", msg); strnfmt(buf, 256, "STATE__BOLD:%^s", who); borg_react(msg, buf); return; } /* Feature XXX XXX XXX */ if (streq(msg, "The door appears to be broken.")) { /* Only process open doors */ if (ag->feat == FEAT_OPEN) { /* Mark as broken */ ag->feat = FEAT_BROKEN; } return; } /* Feature XXX XXX XXX */ if (streq(msg, "The door appears to be stuck.")) { /* Only process non-jammed doors */ if ((ag->feat >= FEAT_DOOR_HEAD) && (ag->feat <= FEAT_DOOR_HEAD + 0x07)) { /* Mark the door as jammed */ ag->feat = FEAT_DOOR_HEAD + 0x08; /* Clear goals */ goal = 0; } return; } #if 0 /* Feature XXX XXX XXX */ if (streq(msg, "This seems to be permanent rock.")) { /* Skip granite walls */ if (ag->feat == FEAT_WALL_EXTRA) continue; /* Only process walls */ if ((ag->feat >= FEAT_WALL_EXTRA) && (ag->feat <= FEAT_PERM_SOLID)) { /* Mark the wall as permanent */ ag->feat = FEAT_PERM_SOLID; /* Clear goals */ goal = 0; } return; } /* Feature XXX XXX XXX */ if (streq(msg, "You tunnel into the granite wall.")) { /* Skip granite walls */ if (ag->feat == FEAT_WALL_EXTRA) continue; /* Only process walls */ if ((ag->feat >= FEAT_WALL_EXTRA) && (ag->feat <= FEAT_PERM_SOLID)) { /* Mark the wall as granite */ ag->feat = FEAT_WALL_EXTRA; /* Clear goals */ goal = 0; } return; } #endif /* Feature XXX XXX XXX */ if (streq(msg, "You tunnel into the quartz vein.")) { /* Process magma veins with treasure */ if (ag->feat == FEAT_MAGMA_K) { /* Mark the vein */ ag->feat = FEAT_QUARTZ_K; /* Clear goals */ goal = 0; } /* Process magma veins */ else if (ag->feat == FEAT_MAGMA) { /* Mark the vein */ ag->feat = FEAT_QUARTZ; /* Clear goals */ goal = 0; } return; } /* Feature XXX XXX XXX */ if (streq(msg, "You tunnel into the magma vein.")) { /* Process quartz veins with treasure */ if (ag->feat == FEAT_QUARTZ_K) { /* Mark the vein */ ag->feat = FEAT_MAGMA_K; /* Clear goals */ goal = 0; } /* Process quartz veins */ else if (ag->feat == FEAT_QUARTZ) { /* Mark the vein */ ag->feat = FEAT_MAGMA; /* Clear goals */ goal = 0; } return; } /* Word of Recall -- Ignition */ if (prefix(msg, "The air about you becomes ")) { /* Initiate recall */ goal_recalling = TRUE; return; } /* Word of Recall -- Lift off */ if (prefix(msg, "You feel yourself yanked ")) { /* Recall complete */ goal_recalling = FALSE; finished_level = FALSE; return; } /* Word of Recall -- Cancelled */ if (prefix(msg, "A tension leaves ")) { /* Hack -- Oops */ goal_recalling = FALSE; return; } /* protect from evil */ if (prefix(msg, "You feel safe from evil!")) { borg_prot_from_evil = TRUE; return; } if (prefix(msg, "You no longer feel safe from evil.")) { borg_prot_from_evil = FALSE; return; } /* haste self */ if (prefix(msg, "You feel yourself moving faster!")) { borg_speed = TRUE; return; } if (prefix(msg, "You feel yourself slow down.")) { borg_speed = FALSE; return; } /* Bless */ if (prefix(msg, "You feel righteous!")) { borg_bless = TRUE; return; } if (prefix(msg, "The prayer has expired.")) { borg_bless = FALSE; return; } /* resist acid */ if (prefix(msg, "You feel resistant to acid!")) { borg_temp_acid = TRUE; return; } if (prefix(msg, "You feel less resistant to acid.")) { borg_temp_acid = FALSE; return; } /* resist electricity */ if (prefix(msg, "You feel resistant to electricity!")) { borg_temp_elec = TRUE; return; } if (prefix(msg, "You feel less resistant to electricity.")) { borg_temp_elec = FALSE; return; } /* resist fire */ if (prefix(msg, "You feel resistant to fire!")) { borg_temp_fire = TRUE; return; } if (prefix(msg, "You feel less resistant to fire.")) { borg_temp_fire = FALSE; return; } /* resist cold */ if (prefix(msg, "You feel resistant to cold!")) { borg_temp_cold = TRUE; return; } if (prefix(msg, "You feel less resistant to cold.")) { borg_temp_cold = FALSE; return; } /* resist poison */ if (prefix(msg, "You feel resistant to poison!")) { borg_temp_poison = TRUE; return; } if (prefix(msg, "You feel less resistant to poison.")) { borg_temp_poison = FALSE; return; } /* GOI! */ if (prefix(msg, "You feel invulnerable!")) { borg_goi = 11; /* keep track of how long it has left (a guess) */ return; } if (prefix(msg, "You feel vulnerable once more.")) { borg_goi = 0; return; } /* Shield */ if (prefix(msg, "A mystic shield forms around your body!")) { borg_shield = TRUE; return; } if (prefix(msg, "Your mystic shield crumbles away.")) { borg_shield = FALSE; return; } /* Feelings about the level */ for (i = 0; prefix_feeling[i]; i++) { /* "You feel..." (etc) */ if (prefix(msg, prefix_feeling[i])) { strnfmt(buf, 256, "FEELING:%d", i); borg_react(msg, buf); return; } } } /* * Parse a message, piece of a message, or set of messages. * * We must handle long messages which are "split" into multiple * pieces, and also multiple messages which may be "combined" * into a single set of messages. */ static void borg_parse(cptr msg) { static char len = 0; static char buf[1024]; /* Flush messages */ if (len && (!msg || (msg[0] != ' '))) { int i, j; /* Split out punctuation */ for (j = i = 0; i < len-1; i++) { /* Check for punctuation */ if ((buf[i] == '.') || (buf[i] == '!') || (buf[i] == '?') || (buf[i] == '"')) { /* Require space */ if (buf[i+1] == ' ') { /* Terminate */ buf[i+1] = '\0'; /* Parse fragment */ borg_parse_aux(buf + j, (i + 1) - j); /* Restore */ buf[i+1] = ' '; /* Advance past spaces */ for (j = i + 2; buf[j] == ' '; j++) /* loop */; } } } /* Parse tail */ borg_parse_aux(buf + j, len - j); /* Forget */ len = 0; } /* No message */ if (!msg) { /* Start over */ len = 0; } /* Continued message */ else if (msg[0] == ' ') { /* Collect, verify, and grow */ len += strnfmt(buf+len, 1024-len, "%s", msg+1); } /* New message */ else { /* Collect, verify, and grow */ len = strnfmt(buf, 1024, "%s", msg); } } /* * XXX XXX XXX Mega-Hack -- keypress stealer from "z-term.c" */ extern errr (*Term_inkey_hook)(char *ch, bool wait, bool take); /* * This function lets the Borg "steal" control from the user. * * The "z-term.c" file provides a special hook which we use to * bypass the standard "Term_flush()" and "Term_inkey()" functions * and replace them with the function below. * * The only way that the Borg can be stopped once it is started, * unless it dies or encounters an error, is to press any key. * This function checks for user input on a regular basic, and * when any is encountered, it relinquishes control gracefully. * * We handle "broken" messages, in which long messages are "broken" * into pieces, and all but the first message are "indented" by one * space, by collecting all the pieces into a complete message and * then parsing the message once it is known to be complete. * * Note the complete hack that allows the Borg to run in "demo" * mode, which allows the Borg to cheat death 100 times, and stamps * the number of cheats in the player "age" field. XXX XXX XXX * * Note that this function hook automatically removes itself when * it realizes that it should no longer be active. Note that this * may take place after the game has asked for the next keypress, * but the various "keypress" routines should be able to handle this. * * XXX XXX XXX We do not correctly handle the "take" flag */ static errr Term_inkey_borg(char *ch, bool wait, bool take) { int i, x, y; int visible; byte t_a; char buf[128]; /* XXX XXX XXX */ if (!auto_active) { /* Message */ borg_note("# Removing keypress hook"); /* Remove hook */ Term_inkey_hook = NULL; /* Flush keys */ borg_flush(); /* Clear if needed */ if (ch) (*ch) = '\0'; /* Nothing ready */ return (1); } /* Hack -- flush keys */ if (!ch) { /* Flush keys */ borg_flush(); /* Success */ return (0); } /* Clear the key */ (*ch) = '\0'; /* Always wait for keys */ if (!wait) return (1); /* Check the "cursor state" XXX XXX XXX */ /* Note that the cursor visibility determines whether the */ /* game is asking us for a "command" or for some other key. */ /* This requires that "hilite_player" be FALSE. */ /* Hack -- Extract the cursor visibility */ (void)Term_get_cursor(&visible); /* XXX XXX XXX Mega-Hack -- Catch "Die? [y/n]" messages */ /* Hack -- cheat death */ if (visible && (0 == Term_locate(&x, &y)) && (y == 0) && (x >= 4) && (0 == borg_what_text(0, 0, 4, &t_a, buf)) && (prefix(buf, "Die?"))) { /* Take note */ borg_note("# Cheating death..."); if (borg_cheat_death) /* Cheat death */ (*ch) = 'n'; else /* This will allow the user to decide what to do next. */ /* if it is used in combination with auto_save you can go back to */ /* before the borg died and replay the dieing moves! */ borg_oops("death"); /* Success */ return (0); } /* XXX XXX XXX Mega-Hack -- Catch "-more-" messages */ /* If the cursor is visible... */ /* And the cursor is on the top line... */ /* And there is text before the cursor... */ /* And that text is "-more-" */ if (visible && (0 == Term_locate(&x, &y)) && (y == 0) && (x >= 7) && (0 == borg_what_text(x-7, y, 7, &t_a, buf)) && (streq(buf, " -more-"))) { /* Get the message */ if (0 == borg_what_text(0, 0, x-7, &t_a, buf)) { /* Parse it */ borg_parse(buf); } /* Hack -- not active */ if (!auto_active) return (1); /* Clear the message */ (*ch) = ' '; /* Done */ return (0); } /* XXX XXX XXX Mega-Hack -- catch normal messages */ /* If the cursor is NOT visible... */ /* And there is text on the first line... */ if (!visible && (0 == borg_what_text(0, 0, 3, &t_a, buf)) && (t_a == TERM_WHITE) && buf[0] && ((buf[0] != ' ') || (buf[1] != ' ') || (buf[2] != ' '))) { /* Get the message */ if (0 == borg_what_text(0, 0, -80, &t_a, buf)) { int k = strlen(buf); /* Strip trailing spaces */ while ((k > 0) && (buf[k-1] == ' ')) k--; /* Terminate */ buf[k] = '\0'; /* Parse it */ borg_parse(buf); } /* Hack -- not active */ if (!auto_active) return (1); /* Clear the message */ (*ch) = ' '; /* Done */ return (0); } /* Flush messages */ borg_parse(NULL); /* Check for key */ i = borg_inkey(FALSE); /* Need more keys */ if (!i) { /* Hack -- Process events (do not wait) */ (void)Term_xtra(TERM_XTRA_EVENT, FALSE); /* Hack -- User Abort XXX XXX XXX */ if (Term->key_head != Term->key_tail) { /* Take note */ borg_note("# Preparing to abort"); /* Cancel later */ auto_cancel = TRUE; /* Hack -- Forget all keypresses */ Term->key_head = Term->key_tail = 0; /* Hack -- Flush all events */ (void)Term_xtra(TERM_XTRA_FLUSH, 0); } /* XXX XXX XXX */ if (death) { /* Oops */ borg_oops("unexpected death!"); /* Return */ return (1); } /* Save the system random info */ auto_rand_quick = Rand_quick; auto_rand_value = Rand_value; /* Use the local random info */ Rand_quick = TRUE; Rand_value = auto_rand_local; /* Update and Think */ while (!borg_think()) /* loop */; /* Save the local random info */ auto_rand_local = Rand_value; /* Restore the system random info */ Rand_quick = auto_rand_quick; Rand_value = auto_rand_value; /* Hack -- allow stepping to induce a clean cancel */ if (auto_step && (!--auto_step)) auto_cancel = TRUE; } /* Check for key */ i = borg_inkey(take); /* Use it */ if (!i) { /* Oops */ borg_oops("user abort"); /* Hack -- Escape! */ i = ESCAPE; } /* Enqueue the keypress */ (*ch) = i; /* Success */ return (0); } /* * Initialize the Borg */ void borg_init_9(void) { int i; byte t_a; char buf[80]; byte *test; /*** Hack -- verify system ***/ /* Message */ prt("Initializing the Borg... (memory)", 0, 0); /* Hack -- flush it */ Term_fresh(); /* Mega-Hack -- verify memory */ C_MAKE(test, 400 * 1024L, byte); C_KILL(test, 400 * 1024L, byte); /*** Hack -- initialize game options ***/ /* Message */ prt("Initializing the Borg... (options)", 0, 0); /* Hack -- flush it */ Term_fresh(); /* We use the original keypress codes */ rogue_like_commands = FALSE; /* We pick up items when we step on them */ always_pickup = TRUE; /* We specify targets by hand */ use_old_target = FALSE; /* We do NOT query any commands */ carry_query_flag = FALSE; other_query_flag = FALSE; /* We repeat by hand */ always_repeat = FALSE; /* We do not haggle */ auto_haggle = TRUE; /* do not start out auto-scumming. */ auto_scum = FALSE; /* We need space */ show_labels = FALSE; show_weights = FALSE; /* We need color */ use_color = TRUE; /* We need the dungeon level */ depth_in_feet = FALSE; /* Allow items to stack */ stack_allow_items = TRUE; /* Allow wands to stack */ stack_allow_wands = TRUE; /* Ignore discounts */ stack_force_costs = TRUE; /* Ignore inscriptions */ stack_force_notes = TRUE; /* Efficiency */ avoid_abort = TRUE; /* Efficiency */ hitpoint_warn = 0; /* Hack -- notice "command" mode */ hilite_player = FALSE; /* Hack -- reset visuals */ reset_visuals(); /* Hack -- Redraw */ do_cmd_redraw(); /*** Various ***/ /* Message */ prt("Initializing the Borg... (various)", 0, 0); /* Hack -- flush it */ Term_fresh(); /*** Cheat / Panic ***/ /* Mega-Hack -- Cheat a lot */ auto_cheat_inven = TRUE; auto_cheat_equip = TRUE; /* Mega-Hack -- Cheat a lot */ auto_cheat_spell = TRUE; /* Mega-Hack -- Cheat a lot */ auto_cheat_panel = TRUE; /* more cheating */ borg_cheat_death = FALSE; /*** Initialize ***/ /* Initialize */ borg_init_1(); borg_init_2(); borg_init_3(); borg_init_4(); borg_init_5(); borg_init_6(); borg_init_7(); borg_init_8(); /*** Hack -- Extract race ***/ /* Check for textual race */ if (0 == borg_what_text(COL_RACE, ROW_RACE, -12, &t_a, buf)) { /* Scan the races */ for (i = 0; i < 10; i++) { /* Check the race */ if (prefix(buf, race_info[i].title)) { /* We got one */ auto_race = i; break; } } } /* Extract the race pointer */ rb_ptr = &race_info[auto_race]; /*** Hack -- Extract class ***/ /* Check for textual class */ if (0 == borg_what_text(COL_CLASS, ROW_CLASS, -12, &t_a, buf)) { /* Scan the classes */ for (i = 0; i < 6; i++) { /* Check the race */ if (prefix(buf, class_info[i].title)) { /* We got one */ auto_class = i; break; } } } /* Extract the class pointer */ cb_ptr = &class_info[auto_class]; /* Extract the magic pointer */ mb_ptr = &magic_info[auto_class]; /*** Hack -- react to race and class ***/ /* Notice the new race and class */ prepare_race_class_info(); /*** All done ***/ /* Done initialization */ prt("Initializing the Borg... done.", 0, 0); /* Clear line */ prt("", 0, 0); /* Official message */ borg_note("# Ready..."); /* Now it is ready */ initialized = TRUE; } /* * Hack -- forward declare */ void do_cmd_borg(void); /* * Hack -- interact with the "Ben Borg". */ void do_cmd_borg(void) { char cmd; /* Get a "Borg command", or abort */ if (!get_com("Borg command: ", &cmd)) return; /* Simple help */ if (cmd == '?') { int i = 2; /* Save the screen */ Term_save(); /* Clear the screen */ Term_clear(); /* Dump commands */ Term_putstr(5, i++, -1, TERM_WHITE, "Command '?' displays this screen."); Term_putstr(5, i++, -1, TERM_WHITE, "Command '$' initializes the Borg."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'z' activates the Borg."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'u' updates the Borg."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'x' steps the Borg."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'f' modifies the normal flags."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'c' modifies the cheat flags."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'l' activates a log file."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 's' activates search mode."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'i' displays grid info."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'g' displays grid feature."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'a' displays avoidances."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'k' displays monster info."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 't' displays object info."); Term_putstr(5, i++, -1, TERM_WHITE, "Command '%' displays current flow."); Term_putstr(5, i++, -1, TERM_WHITE, "Command '#' displays danger grid."); Term_putstr(5, i++, -1, TERM_WHITE, "Command '_' Depth info."); Term_putstr(5, i++, -1, TERM_WHITE, "Command 'p' Borg Power."); /* Prompt for key */ msg_print("Available commands: ?,$,z,u,x,f,c,w,l,s,i,a,k,t,%,#,_,p."); msg_print(NULL); /* Restore the screen */ Term_load(); /* Done */ return; } /* Hack -- force initialization */ if (!initialized) borg_init_9(); switch (cmd) { /* Command: Nothing */ case '$': { break; } /* Command: Activate */ case 'z': case 'Z': { /* Activate */ auto_active = TRUE; /* Reset cancel */ auto_cancel = FALSE; /* Step forever */ auto_step = 0; /* need to check all stats */ my_need_stat_check[0] = TRUE; my_need_stat_check[1] = TRUE; my_need_stat_check[2] = TRUE; my_need_stat_check[3] = TRUE; my_need_stat_check[4] = TRUE; my_need_stat_check[5] = TRUE; /* Allowable Cheat -- Obtain "recall" flag */ goal_recalling = (p_ptr->word_recall ? TRUE : FALSE); /* Allowable Cheat -- Obtain "prot_from_evil" flag */ borg_prot_from_evil = (p_ptr->protevil ? TRUE : FALSE); /* Allowable Cheat -- Obtain "speed" flag */ borg_speed = (p_ptr->fast ? TRUE : FALSE); /* Allowable Cheat -- Obtain "goi" flag */ borg_goi = (p_ptr->invuln ? 9 : 0); /* Allowable Cheat -- Obtain "resist" flags */ borg_temp_acid = (p_ptr->oppose_acid ? TRUE : FALSE); borg_temp_elec = (p_ptr->oppose_elec ? TRUE : FALSE); borg_temp_fire = (p_ptr->oppose_fire ? TRUE : FALSE); borg_temp_cold = (p_ptr->oppose_cold ? TRUE : FALSE); borg_temp_poison = (p_ptr->oppose_pois ? TRUE : FALSE); borg_bless = (p_ptr->blessed ? TRUE : FALSE); borg_shield = (p_ptr->shield ? TRUE : FALSE); #if 0 /*!FIX AJG not coded yet */. borg_hero = (p_ptr->hero ? TRUE : FALSE); if (!borg_hero) borg_hero = (p_ptr->shero ? TRUE : FALSE); #endif /* Message */ borg_note("# Installing keypress hook"); /* Activate the key stealer */ Term_inkey_hook = Term_inkey_borg; break; } /* Command: Update */ case 'u': case 'U': { /* Activate */ auto_active = TRUE; /* Immediate cancel */ auto_cancel = TRUE; /* Step forever */ auto_step = 0; /* Allowable Cheat -- Obtain "recall" flag */ goal_recalling = (p_ptr->word_recall ? TRUE : FALSE); /* Allowable Cheat -- Obtain "prot_from_evil" flag */ borg_prot_from_evil = (p_ptr->protevil ? TRUE : FALSE); /* Allowable Cheat -- Obtain "speed" flag */ borg_speed = (p_ptr->fast ? TRUE : FALSE); /* Allowable Cheat -- Obtain "goi" flag */ borg_goi = (p_ptr->invuln ? 9 : 0); /* Allowable Cheat -- Obtain "resist" flags */ borg_temp_acid = (p_ptr->oppose_acid ? TRUE : FALSE); borg_temp_elec = (p_ptr->oppose_elec ? TRUE : FALSE); borg_temp_fire = (p_ptr->oppose_fire ? TRUE : FALSE); borg_temp_cold = (p_ptr->oppose_cold ? TRUE : FALSE); borg_temp_poison = (p_ptr->oppose_pois ? TRUE : FALSE); borg_bless = (p_ptr->blessed ? TRUE : FALSE); borg_shield = (p_ptr->shield ? TRUE : FALSE); #if 0 /*!FIX AJG not coded yet */. borg_hero = (p_ptr->hero ? TRUE : FALSE); if (!borg_hero) borg_hero = (p_ptr->shero ? TRUE : FALSE); #endif /* Message */ borg_note("# Installing keypress hook"); /* Activate the key stealer */ Term_inkey_hook = Term_inkey_borg; break; } /* Command: Step */ case 'x': case 'X': { /* Activate */ auto_active = TRUE; /* Reset cancel */ auto_cancel = FALSE; /* Step for one (or more) turns */ auto_step = (command_arg > 0) ? command_arg : 1; /* need to check all stats */ my_need_stat_check[0] = TRUE; my_need_stat_check[1] = TRUE; my_need_stat_check[2] = TRUE; my_need_stat_check[3] = TRUE; my_need_stat_check[4] = TRUE; my_need_stat_check[5] = TRUE; /* Allowable Cheat -- Obtain "recall" flag */ goal_recalling = (p_ptr->word_recall ? TRUE : FALSE); /* Allowable Cheat -- Obtain "prot_from_evil" flag */ borg_prot_from_evil = (p_ptr->protevil ? TRUE : FALSE); /* Allowable Cheat -- Obtain "speed" flag */ borg_speed = (p_ptr->fast ? TRUE : FALSE); /* Allowable Cheat -- Obtain "goi" flag */ borg_goi = (p_ptr->invuln ? 9 : 0); /* Allowable Cheat -- Obtain "resist" flags */ borg_temp_acid = (p_ptr->oppose_acid ? TRUE : FALSE); borg_temp_elec = (p_ptr->oppose_elec ? TRUE : FALSE); borg_temp_fire = (p_ptr->oppose_fire ? TRUE : FALSE); borg_temp_cold = (p_ptr->oppose_cold ? TRUE : FALSE); borg_temp_poison = (p_ptr->oppose_pois ? TRUE : FALSE); borg_bless = (p_ptr->blessed ? TRUE : FALSE); borg_shield = (p_ptr->shield ? TRUE : FALSE); #if 0 /*!FIX AJG not coded yet */. borg_hero = (p_ptr->hero ? TRUE : FALSE); if (!borg_hero) borg_hero = (p_ptr->shero ? TRUE : FALSE); #endif /* Message */ borg_note("# Installing keypress hook"); /* Activate the key stealer */ Term_inkey_hook = Term_inkey_borg; break; } /* Command: toggle "flags" */ case 'f': case 'F': { /* Get a "Borg command", or abort */ if (!get_com("Borg command: Toggle Flag: (d/s/f) ", &cmd)) return; switch (cmd) { /* Dump savefile at each death */ case 'd': case 'D': { auto_flag_dump = !auto_flag_dump; msg_format("Borg -- auto_flag_dump is now %d.", auto_flag_dump); break; } /* Dump savefile at each level */ case 's': case 'S': { auto_flag_save = !auto_flag_save; msg_format("Borg -- auto_flag_save is now %d.", auto_flag_save); break; } /* clear 'fear' levels */ case 'f': case 'F': { msg_format("Command No Longer Usefull"); break; } } break; } /* Command: toggle "cheat" flags */ case 'c': case 'C': { /* Get a "Borg command", or abort */ if (!get_com("Borg command: Toggle Cheat: (d/i/e/s/p)", &cmd)) return; switch (cmd) { case 'd': case 'D': { borg_cheat_death = !borg_cheat_death; msg_format("Borg -- auto_cheat_death is now %d.", borg_cheat_death); break; } case 'i': case 'I': { auto_cheat_inven = !auto_cheat_inven; msg_format("Borg -- auto_cheat_inven is now %d.", auto_cheat_inven); break; } case 'e': case 'E': { auto_cheat_equip = !auto_cheat_equip; msg_format("Borg -- auto_cheat_equip is now %d.", auto_cheat_equip); break; } case 's': case 'S': { auto_cheat_spell = !auto_cheat_spell; msg_format("Borg -- auto_cheat_spell is now %d.", auto_cheat_spell); break; } case 'p': case 'P': { auto_cheat_panel = !auto_cheat_panel; msg_format("Borg -- auto_cheat_panel is now %d.", auto_cheat_panel); break; } } break; } /* Start a new log file */ case 'l': case 'L': { char buf[80]; /* Close the log file */ if (auto_fff) my_fclose(auto_fff); /* Hack -- drop permissions */ safe_setuid_drop(); /* Default */ strcpy(buf, "borg.log"); /* XXX XXX XXX Get the name and open the log file */ if (get_string("Borg Log File: ", buf, 70)) { /* Open a new file */ auto_fff = my_fopen(buf, "w"); /* Failure */ if (!auto_fff) msg_print("Cannot open that file."); } /* Hack -- grab permissions */ safe_setuid_grab(); } /* Activate a search string */ case 's': case 'S': { /* Get the new search string (or cancel the matching) */ if (!get_string("Borg Match String: ", auto_match, 70)) { /* Cancel it */ strcpy(auto_match, ""); /* Message */ msg_print("Borg Match String de-activated."); } break; } /* Command: check Grid "feature" flags */ case 'g': case 'G': { int x, y; u16b low, high; /* Get a "Borg command", or abort */ if (!get_com("Borg command: Show grids: ", &cmd)) return; /* Extract a flag */ switch (cmd) { case '0': low = high = 1 << 0; break; case '1': low = high = 1 << 1; break; case '2': low = high = 1 << 2; break; case '3': low = high = 1 << 3; break; case '4': low = high = 1 << 4; break; case '5': low = high = 1 << 5; break; case '6': low = high = 1 << 6; break; case '7': low = high = 1 << 7; break; case '.': low = high = FEAT_FLOOR; break; case ' ': low = high = FEAT_NONE; break; case 'i': low = high = FEAT_INVIS; break; case ';': low = high = FEAT_GLYPH; break; case ',': low = high = FEAT_OPEN; break; case 'x': low = high = FEAT_BROKEN; break; case '>': low = high = FEAT_LESS; break; case '<': low = high = FEAT_MORE; break; case '@': low = FEAT_SHOP_HEAD; high = FEAT_SHOP_TAIL; break; case '^': low = FEAT_TRAP_HEAD; high = FEAT_TRAP_TAIL; break; case '+': low = FEAT_DOOR_HEAD; break; high = FEAT_DOOR_TAIL; break; case 's': low = high = FEAT_SECRET; break; case ':': low = high = FEAT_RUBBLE; break; case 'm': low = high = FEAT_MAGMA; break; case 'q': low = high = FEAT_QUARTZ; break; case 'r': low = high = FEAT_QUARTZ_H; break; case 'k': low = high = FEAT_MAGMA_K; break; case '&': low = high = FEAT_QUARTZ_K; break; case 'w': low = FEAT_WALL_EXTRA; high = FEAT_WALL_SOLID; break; case 'p': low = FEAT_PERM_EXTRA; high = FEAT_PERM_SOLID; break; default: low = high = 0x00; break; } /* Scan map */ for (y = w_y; y < w_y + SCREEN_HGT; y++) { for (x = w_x; x < w_x + SCREEN_WID; x++) { byte a = TERM_RED; auto_grid *ag = &auto_grids[y][x]; /* show only those grids */ if (!(ag->feat >= low && ag->feat <= high)) continue; /* Color */ if (borg_cave_floor_bold(y, x)) a = TERM_YELLOW; /* Display */ print_rel('*', a, y, x); } } /* Get keypress */ msg_print("Press any key."); msg_print(NULL); /* Redraw map */ prt_map(); break; } /* Command: check "info" flags */ case 'i': case 'I': { int x, y; u16b mask; /* Get a "Borg command", or abort */ if (!get_com("Borg command: Show grids: ", &cmd)) return; /* Extract a flag */ switch (cmd) { case '0': mask = 1 << 0; break; case '1': mask = 1 << 1; break; case '2': mask = 1 << 2; break; case '3': mask = 1 << 3; break; case '4': mask = 1 << 4; break; case '5': mask = 1 << 5; break; case '6': mask = 1 << 6; break; case '7': mask = 1 << 7; break; case 'm': mask = BORG_MARK; break; case 'g': mask = BORG_GLOW; break; case 'd': mask = BORG_DARK; break; case 'o': mask = BORG_OKAY; break; case 'l': mask = BORG_LITE; break; case 'v': mask = BORG_VIEW; break; case 't': mask = BORG_TEMP; break; case 'x': mask = BORG_XTRA; break; default: mask = 0x00; break; } /* Scan map */ for (y = w_y; y < w_y + SCREEN_HGT; y++) { for (x = w_x; x < w_x + SCREEN_WID; x++) { byte a = TERM_RED; auto_grid *ag = &auto_grids[y][x]; /* Given mask, show only those grids */ if (mask && !(ag->info & mask)) continue; /* Given no mask, show unknown grids */ if (!mask && (ag->info & BORG_MARK)) continue; /* Color */ if (borg_cave_floor_bold(y, x)) a = TERM_YELLOW; /* Display */ print_rel('*', a, y, x); } } /* Get keypress */ msg_print("Press any key."); msg_print(NULL); /* Redraw map */ prt_map(); break; } /* Command: check "avoidances" */ case 'a': case 'A': { int x, y, p; /* Scan map */ for (y = w_y; y < w_y + SCREEN_HGT; y++) { for (x = w_x; x < w_x + SCREEN_WID; x++) { byte a = TERM_RED; /* Obtain danger */ p = borg_danger(y, x, 1); /* Skip non-avoidances */ if (p <= avoidance / 2) continue; /* Use yellow for less painful */ if (p <= avoidance) a = TERM_YELLOW; /* Display */ print_rel('*', a, y, x); } } /* Get keypress */ msg_format("Avoidance value %d.", avoidance); msg_print(NULL); /* Redraw map */ prt_map(); break; } /* Command: show "monsters" */ case 'k': case 'K': { int i, n = 0; /* Scan the monsters */ for (i = 1; i < auto_kills_nxt; i++) { auto_kill *kill = &auto_kills[i]; /* Still alive */ if (kill->r_idx) { int x = kill->x; int y = kill->y; /* Display */ print_rel('*', TERM_RED, y, x); /* Count */ n++; } } /* Get keypress */ msg_format("There are %d known monsters.", n); msg_print(NULL); /* Redraw map */ prt_map(); break; } /* Command: show "objects" */ case 't': case 'T': { int i, n = 0; /* Scan the objects */ for (i = 1; i < auto_takes_nxt; i++) { auto_take *take = &auto_takes[i]; /* Still alive */ if (take->k_idx) { int x = take->x; int y = take->y; /* Display */ print_rel('*', TERM_RED, y, x); /* Count */ n++; } } /* Get keypress */ msg_format("There are %d known objects.", n); msg_print(NULL); /* Redraw map */ prt_map(); break; } /* Command: debug -- current flow */ case '%': { int i, x, y; /* Flow */ for (i = 0; i < 250; i++) { int n = 0; /* Scan map */ for (y = w_y; y < w_y + SCREEN_HGT; y++) { for (x = w_x; x < w_x + SCREEN_WID; x++) { byte a = TERM_RED; /* Verify flow cost */ if (auto_data_flow->data[y][x] != i) continue; /* Display */ print_rel('*', a, y, x); /* Count */ n++; } } /* Nothing */ if (!n) break; /* Get keypress */ msg_format("Flow depth %d.", i); msg_print(NULL); /* Redraw map */ prt_map(); } break; } /* Command: debug -- danger of grid */ case '#': { int n; /* Turns */ n = (command_arg ? command_arg : 1); /* Danger of grid */ msg_format("Danger(%d,%d,%d) is %d", target_col, target_row, n, borg_danger(target_row, target_col, n)); break; } /* Command: debug -- fear of depth */ case '_': { /* Max depth */ msg_format("Max depth %d, ", auto_max_depth); /* Fear depth */ msg_format("Fear depth %d, ", fear_depth); /* Dump fear codes */ msg_format("times completed fear depth %d", auto_fear_depth); break; } /* Command: debug -- Power */ case 'p': case 'P': { s32b p; /* Examine the screen */ borg_update_frame(); /* Examine the screen */ borg_update(); /* Cheat the "equip" screen */ borg_cheat_equip(); /* Cheat the "inven" screen */ borg_cheat_inven(); /* Extract some "hidden" variables */ borg_hidden(); /* Examine the inventory */ borg_notice(); /* Evaluate */ p = borg_power(); /* Max depth */ msg_format("Current Borg Power %ld", p); break; } /* Command: Show time */ case '!': { s32b time = c_t - auto_began; msg_format("time: (%d) ", time); time = (auto_time_town + (c_t - auto_began)); msg_format("time from town (%d)", time); break; } /* Command: my Stats */ case '@': msg_format("str (m%d,c%d)", my_stat_max[0], my_stat_cur[0]); msg_format("int (m%d,c%d)", my_stat_max[1], my_stat_cur[1]); msg_format("wis (m%d,c%d)", my_stat_max[2], my_stat_cur[2]); msg_format("dex (m%d,c%d)", my_stat_max[3], my_stat_cur[3]); msg_format("con (m%d,c%d)", my_stat_max[4], my_stat_cur[4]); msg_format("cha (m%d,c%d)", my_stat_max[5], my_stat_cur[5]); break; /* Oops */ default: { /* Message */ msg_print("That is not a legal Borg command."); break; } } } #else #ifdef MACINTOSH static int HACK = 0; #endif #endif