/* File: borg8.c */ /* * Copyright (c) 1997 Ben Harrison * * This software may be copied and distributed for educational, research, * and not for profit purposes provided that this copyright and statement * are included in all such copies. */ #include "angband.h" #include "borg.h" #ifdef ALLOW_BORG /* * Mega-Hack -- extract some "hidden" variables * * XXX XXX XXX This step would not be necessary if more info * was available on the screen. Perhaps we should track the * maximal value of "b_ptr->stat_cur" so we have "b_ptr->stat_max". */ static void borg_hidden(void) { int i; int stat_add[6]; /* Clear "stat_add[]" */ for (i = 0; i < 6; i++) stat_add[i] = 0; /* Scan the equipment */ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) { auto_item *item = &borg_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Affect stats */ if (item->flags1 & TR1_STR) stat_add[A_STR] += item->pval; if (item->flags1 & TR1_INT) stat_add[A_INT] += item->pval; if (item->flags1 & TR1_WIS) stat_add[A_WIS] += item->pval; if (item->flags1 & TR1_DEX) stat_add[A_DEX] += item->pval; if (item->flags1 & TR1_CON) stat_add[A_CON] += item->pval; if (item->flags1 & TR1_CHR) stat_add[A_CHR] += item->pval; } /* Mega-Hack -- Guess at "b_ptr->stat_cur[]" */ for (i = 0; i < 6; i++) { int value; /* Hack -- reverse the known bonus */ value = modify_stat_value(borg_base_stat[i], -stat_add[i]); /* Hack -- save the maximum/current stats */ b_ptr->stat_max[i] = b_ptr->stat_cur[i] = value; } } /* * Object flags -- name */ static cptr info_name[96] = { "STR", "INT", "WIS", "DEX", "CON", "CHR", "XXX1", "XXX2", "STEALTH", "SEARCH", "INFRA", "TUNNEL", "SPEED", "BLOWS", "SHOTS", "MIGHT", "SLAY_ANIMAL", "SLAY_EVIL", "SLAY_UNDEAD", "SLAY_DEMON", "SLAY_ORC", "SLAY_TROLL", "SLAY_GIANT", "SLAY_DRAGON", "KILL_DRAGON", "XXX5", "XXX6", "XXX7", "BRAND_ACID", "BRAND_ELEC", "BRAND_FIRE", "BRAND_COLD", "SUST_STR", "SUST_INT", "SUST_WIS", "SUST_DEX", "SUST_CON", "SUST_CHR", "XXX1", "XXX2", "XXX3", "XXX4", "XXX5", "XXX6", "IM_ACID", "IM_ELEC", "IM_FIRE", "IM_COLD", "RES_ACID", "RES_ELEC", "RES_FIRE", "RES_COLD", "RES_POIS", "RES_FEAR", "RES_LITE", "RES_DARK", "RES_BLIND", "RES_CONFU", "RES_SOUND", "RES_SHARD", "RES_NEXUS", "RES_NETHR", "RES_CHAOS", "RES_DISEN", "SLOW_DIGEST", "FEATHER", "LITE", "REGEN", "TELEPATHY", "SEE_INVIS", "FREE_ACT", "HOLD_LIFE", "XXX1", "XXX2", "XXX3", "XXX4", "IMPACT", "TELEPORT", "AGGRAVATE", "DRAIN_EXP", "IGNORE_ACID", "IGNORE_ELEC", "IGNORE_FIRE", "IGNORE_COLD", "XXX5", "XXX6", "BLESSED", "ACTIVATE", "INSTA_ART", "EASY_KNOW", "HIDE_TYPE", "SHOW_MODS", "XXX7", "LIGHT_CURSE", "HEAVY_CURSE", "PERMA_CURSE" }; /* * Object flags -- text */ static cptr info_text[96] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "It sustains your strength.", "It sustains your intelligence.", "It sustains your wisdom.", "It sustains your dexterity.", "It sustains your constitution.", "It sustains your charisma.", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "It provides resistance to acid.", "It provides resistance to electricity.", "It provides resistance to fire.", "It provides resistance to cold.", "It provides resistance to poison.", "It provides resistance to fear.", "It provides resistance to light.", "It provides resistance to dark.", "It provides resistance to blindness.", "It provides resistance to confusion.", "It provides resistance to sound.", "It provides resistance to shards.", "It provides resistance to nexus.", "It provides resistance to nether.", "It provides resistance to chaos.", "It provides resistance to disenchantment.", "It slows your metabolism.", "It induces feather falling.", "It provides permanent light.", "It speeds your regenerative powers.", "It gives telepathic powers.", "It allows you to see invisible monsters.", "It provides immunity to paralysis.", "It provides resistance to life draining.", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* * Parse "examination" screen */ static void borg_parse_examine(void) { int y; byte t_a; char buf[80]; /* Parse information */ for (y = 2; y < 22; y++) { /* Get the message */ if (0 == borg_what_text(0, y, -65, &t_a, buf)) { int i; /* Scan flags */ for (i = 0; i < 96; i++) { /* Check info text */ if (info_text[i] && prefix(buf, info_text[i])) { auto_item *item = &borg_items[borg_exam_item]; /* Message */ borg_note(format("Examine found flag '%s'", info_name[i])); /* Notice missing flag */ if (((i / 32 == 0) && !(item->flags1 & (1L << (i % 32)))) || ((i / 32 == 1) && !(item->flags2 & (1L << (i % 32)))) || ((i / 32 == 2) && !(item->flags3 & (1L << (i % 32))))) { /* Message */ borg_note(format("Examine using flag '%s'", info_name[i])); /* XXX XXX XXX XXX */ sprintf(borg_exam_note, "BORG_%s", info_name[i]); } /* Done */ break; } } } } } /* * 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 "borg_cheat_inven()" and "borg_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 * would help us to keep track of how long we have held objects, especially if * we attempt to do "item tracking" in the inventory extraction code. */ bool borg_think(void) { int i; byte t_a; char buf[128]; /*** Handle "examine" screen ***/ /* Only when requested */ if (borg_exam_item >= 0) { /* Note */ borg_note(format("Examining item %d...", borg_exam_item)); /* Examine */ borg_parse_examine(); /* More info XXX XXX XXX */ if ((0 == borg_what_text(15, 22, 10, &t_a, buf)) && (streq(buf, "-- more --"))) { /* See more */ borg_keypress(' '); /* Continue */ return (TRUE); } /* All done */ borg_keypress(ESCAPE); /* Inscribe (if possible) */ if (!streq(borg_exam_note, "")) { /* Inscribe */ borg_send_inscribe_item(borg_exam_item, borg_exam_note); } /* Forget */ borg_exam_item = -1; strcpy(borg_exam_note, ""); /* Done */ return (TRUE); } /*** Process inventory/equipment ***/ /* Cheat */ if (borg_flag_cheat_equip && borg_do_equip) { /* Only do it once */ borg_do_equip = FALSE; /* Cheat the "equip" screen */ borg_cheat_equip(); /* Done */ return (FALSE); } /* Cheat */ if (borg_flag_cheat_inven && borg_do_inven) { /* Only do it once */ borg_do_inven = FALSE; /* Cheat the "inven" screen */ borg_cheat_inven(); /* Done */ return (FALSE); } /* 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 (borg_do_equip) { /* Only do it once */ borg_do_equip = FALSE; /* Enter "equip" mode */ borg_keypress('e'); /* Done */ return (TRUE); } /* Check "inven" */ if (borg_do_inven) { /* Only do it once */ borg_do_inven = FALSE; /* Enter "inven" mode */ borg_keypress('i'); /* Done */ return (TRUE); } /*** Find books ***/ /* Only if needed */ if (borg_do_spell && (borg_do_spell_aux == 0)) { /* Assume no books */ for (i = 0; i < 9; i++) borg_base_book[i] = -1; /* Scan the pack */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &borg_items[i]; /* Skip non-books */ if (item->tval != mb_ptr->spell_book) continue; /* Note book locations */ borg_base_book[item->sval] = i; } } /*** Process books ***/ /* Hack -- Warriors never browse */ if (b_ptr->pclass == 0) borg_do_spell = FALSE; /* Hack -- Blind or Confused prevents browsing */ if (borg_base_is_blind || borg_base_is_confused) borg_do_spell = FALSE; /* XXX XXX XXX Dark */ /* Hack -- Stop doing spells when done */ if (borg_do_spell_aux > 8) borg_do_spell = FALSE; /* Cheat */ if (borg_flag_cheat_spell && borg_do_spell) { /* Look for the book */ i = borg_base_book[borg_do_spell_aux]; /* Cheat the "spell" screens (all of them) */ if (i >= 0) { /* Cheat that page */ borg_cheat_spell(borg_do_spell_aux); } /* Advance to the next book */ borg_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(borg_do_spell_aux); /* Advance to the next book */ borg_do_spell_aux++; /* Leave that mode */ borg_keypress(ESCAPE); /* Done */ return (TRUE); } /* Check "spells" */ if (borg_do_spell) { /* Look for the book */ i = borg_base_book[borg_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 */ borg_do_spell_aux++; /* Done */ return (FALSE); } /*** 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 */ borg_base_shop = 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)) borg_base_shop = i; } } /* Hack -- reset page/more */ borg_shops[borg_base_shop].page = 0; borg_shops[borg_base_shop].more = 0; /* React to new stores */ if (borg_do_browse_what != borg_base_shop) { /* Clear all the items */ for (i = 0; i < 24; i++) { /* XXX Wipe the ware */ WIPE(&borg_shops[borg_base_shop].ware[i], auto_item); } /* Save the store */ borg_do_browse_what = borg_base_shop; } /* Extract the "page", if any */ if ((0 == borg_what_text(20, 5, 8, &t_a, buf)) && (prefix(buf, "(Page "))) /* --)-- */ { /* Take note of the page */ borg_shops[borg_base_shop].more = 1; borg_shops[borg_base_shop].page = (buf[6] - '0') - 1; } /* React to disappearing pages */ if (borg_do_browse_more != borg_shops[borg_base_shop].more) { /* Clear the second page */ for (i = 12; i < 24; i++) { /* XXX Wipe the ware */ WIPE(&borg_shops[borg_base_shop].ware[i], auto_item); } /* Save the new one */ borg_do_browse_more = borg_shops[borg_base_shop].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]) b_ptr->au = 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] == ')') && (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 (borg_base_shop != 7) { if (0 != borg_what_text(68, i + 6, -9, &t_a, cost)) { cost[0] = '\0'; } } } /* Extract actual index */ n = borg_shops[borg_base_shop].page * 12 + i; /* Ignore "unchanged" descriptions */ if (streq(desc, borg_shops[borg_base_shop].ware[n].desc)) continue; /* Analyze the item */ borg_item_analyze(&borg_shops[borg_base_shop].ware[n], desc); /* Hack -- Save the declared cost */ borg_shops[borg_base_shop].ware[n].cost = atol(cost); } /* Hack -- browse as needed */ if (borg_shops[borg_base_shop].more && borg_do_browse) { /* Check next page */ borg_keypress(' '); /* Done browsing */ borg_do_browse = FALSE; /* Done */ return (TRUE); } /* Recheck inventory */ borg_do_inven = TRUE; /* Recheck equipment */ borg_do_equip = TRUE; /* Recheck spells */ borg_do_spell = TRUE; /* Restart spells */ borg_do_spell_aux = 0; /* Hack -- browse again later */ borg_do_browse = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the current world */ borg_base_power = borg_power(); /* Hack -- allow user abort */ if (borg_cancel) return (TRUE); /* Think until done */ return (borg_think_store()); } /*** Determine panel ***/ /* Hack -- cheat */ if (borg_flag_cheat_panel) { /* Steal info XXX XXX XXX */ borg_steal_panel_info(buf); /* Hack -- get the panel info XXX XXX XXX */ xb_ptr->wy = (buf[12] - '0') * PANEL_HGT; xb_ptr->wx = (buf[14] - '0') * PANEL_WID; /* Done */ borg_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 XXX XXX XXX */ xb_ptr->wy = (buf[12] - '0') * PANEL_HGT; xb_ptr->wx = (buf[14] - '0') * PANEL_WID; /* Leave panel mode */ borg_keypress(ESCAPE); /* Done */ return (TRUE); } /* Check equipment */ if (borg_do_panel) { /* Only do it once */ borg_do_panel = FALSE; /* Enter "panel" mode */ borg_keypress('L'); /* Done */ return (TRUE); } /*** Analyze the Frame ***/ /* Analyze the frame */ if (borg_do_frame) { /* Only once */ borg_do_frame = FALSE; /* Analyze the "frame" */ borg_update_frame(); } /*** Re-activate Tests ***/ /* Check equip again later */ borg_do_equip = TRUE; /* Check inven again later */ borg_do_inven = TRUE; /* Check panel again later */ borg_do_panel = TRUE; /* Check frame again later */ borg_do_frame = TRUE; /* Check spells again later */ borg_do_spell = TRUE; /* Hack -- Start the books over */ borg_do_spell_aux = 0; /*** Analyze status ***/ /* Track best level */ if (b_ptr->lev > b_ptr->max_lev) b_ptr->max_lev = b_ptr->lev; if (b_ptr->depth > b_ptr->max_depth) b_ptr->max_depth = b_ptr->depth; /*** Think about it ***/ /* Increment the clock */ borg_time++; /* Examine the screen */ borg_update(); /* Extract some "hidden" variables */ borg_hidden(); /* Examine the equipment/inventory */ borg_notice(); /* Evaluate the current world */ borg_base_power = borg_power(); /* Hack -- allow user abort */ if (borg_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 "drools", "insults", "moans", and "begs you for money" * messages are ignored, since they are totally irrelevant. * * See "make_attack_normal()" for details. */ static cptr suffix_hit_by[] = { " hits you.", /* RBM_HIT */ " touches you.", /* RBM_TOUCH */ " punches you.", /* RBM_PUNCH */ " kicks you.", /* RBM_KICK */ " claws you.", /* RBM_CLAW */ " bites you.", /* RBM_BITE */ " stings you.", /* RBM_STING */ /* xxx */ /* RBM_XXX1 */ " butts you.", /* RBM_BUTT */ " crushes you.", /* RBM_CRUSH */ " engulfs you.", /* RBM_ENGULF */ /* xxx */ /* RBM_XXX2 */ " crawls on you.", /* RBM_CRAWL */ /* xxx */ /* RBM_DROOL */ " spits on you.", /* RBM_SPIT */ /* xxx */ /* RBM_XXX3 */ " gazes at you.", /* RBM_GAZE */ " wails at you.", /* RBM_WAIL */ " releases spores at you.", /* RBM_SPORE */ /* xxx */ /* RBM_XXX4 */ /* xxx */ /* RBM_BEG */ /* xxx */ /* RBM_INSULT */ /* xxx */ /* RBM_MOAN */ /* xxx */ /* RBM_XXX5 */ 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 /* * These messages are not currently matched */ static void some_extra_messages() { /* 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 y = xb_ptr->gy; int x = xb_ptr->gx; int i, tmp; char who[256]; char buf[256]; /* Log (if needed) */ if (borg_fff) borg_info(format("& Msg <%s>", msg)); /* Hack -- Notice death */ if (prefix(msg, "You die.")) { /* Note death */ borg_note("Player died!"); /* Abort */ /* borg_oops("death"); */ /* Abort right now! */ /* borg_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 */ borg_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; /* 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 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 (db_ptr->cave_feat[y][x] == FEAT_OPEN) { /* Mark as broken */ db_ptr->cave_feat[y][x] = FEAT_BROKEN; } return; } /* Feature XXX XXX XXX */ if (streq(msg, "The door appears to be stuck.")) { /* Only process non-jammed doors */ if ((db_ptr->cave_feat[y][x] >= FEAT_DOOR_HEAD) && (db_ptr->cave_feat[y][x] <= FEAT_DOOR_HEAD + 0x07)) { /* Mark the door as jammed */ db_ptr->cave_feat[y][x] = FEAT_DOOR_HEAD + 0x08; /* Forget task */ borg_task = 0; } return; } #if 0 /* Feature XXX XXX XXX */ if (streq(msg, "This seems to be permanent rock.")) { /* Skip granite walls */ if (db_ptr->cave_feat[y][x] == FEAT_WALL_EXTRA) continue; /* Only process walls */ if ((db_ptr->cave_feat[y][x] >= FEAT_WALL_EXTRA) && (db_ptr->cave_feat[y][x] <= FEAT_PERM_SOLID)) { /* Mark the wall as permanent */ db_ptr->cave_feat[y][x] = FEAT_PERM_SOLID; /* Forget task */ borg_task = 0; } return; } /* Feature XXX XXX XXX */ if (streq(msg, "You tunnel into the granite wall.")) { /* Skip granite walls */ if (db_ptr->cave_feat[y][x] == FEAT_WALL_EXTRA) continue; /* Only process walls */ if ((db_ptr->cave_feat[y][x] >= FEAT_WALL_EXTRA) && (db_ptr->cave_feat[y][x] <= FEAT_PERM_SOLID)) { /* Mark the wall as granite */ db_ptr->cave_feat[y][x] = FEAT_WALL_EXTRA; /* Forget task */ borg_task = 0; } return; } #endif /* Feature XXX XXX XXX */ if (streq(msg, "You tunnel into the quartz vein.")) { /* Process magma veins with treasure */ if (db_ptr->cave_feat[y][x] == FEAT_MAGMA_K) { /* Mark the vein */ db_ptr->cave_feat[y][x] = FEAT_QUARTZ_K; /* Forget task */ borg_task = 0; } /* Process magma veins */ else if (db_ptr->cave_feat[y][x] == FEAT_MAGMA) { /* Mark the vein */ db_ptr->cave_feat[y][x] = FEAT_QUARTZ; /* Forget task */ borg_task = 0; } return; } /* Feature XXX XXX XXX */ if (streq(msg, "You tunnel into the magma vein.")) { /* Process quartz veins with treasure */ if (db_ptr->cave_feat[y][x] == FEAT_QUARTZ_K) { /* Mark the vein */ db_ptr->cave_feat[y][x] = FEAT_MAGMA_K; /* Forget task */ borg_task = 0; } /* Process quartz veins */ else if (db_ptr->cave_feat[y][x] == FEAT_QUARTZ) { /* Mark the vein */ db_ptr->cave_feat[y][x] = FEAT_MAGMA; /* Forget task */ borg_task = 0; } return; } /* Word of Recall -- Ignition */ if (prefix(msg, "The air about you becomes ")) { /* Initiate recall */ borg_recalling = TRUE; return; } /* Word of Recall -- Lift off */ if (prefix(msg, "You feel yourself yanked ")) { /* Recall complete */ borg_recalling = FALSE; return; } /* Word of Recall -- Cancelled */ if (prefix(msg, "A tension leaves ")) { /* Hack -- Oops */ borg_recalling = FALSE; return; } #if 0 /* State transitions */ msg_print("You are blind!"); msg_print("You can see again."); msg_print("You are confused!"); msg_print("You feel less confused now."); msg_print("You are poisoned!"); msg_print("You are no longer poisoned."); msg_print("You are terrified!"); msg_print("You feel bolder now."); msg_print("You are paralyzed!"); msg_print("You can move again."); msg_print("You feel drugged!"); msg_print("You can see clearly again."); msg_print("You feel yourself moving faster!"); msg_print("You feel yourself slow down."); msg_print("You feel yourself moving slower!"); msg_print("You feel yourself speed up."); msg_print("A mystic shield forms around your body!"); msg_print("Your mystic shield crumbles away."); msg_print("You feel righteous!"); msg_print("The prayer has expired."); msg_print("You feel like a hero!"); msg_print("The heroism wears off."); msg_print("You feel like a killing machine!"); msg_print("You feel less Berserk."); msg_print("You feel safe from evil!"); msg_print("You no longer feel safe from evil."); msg_print("You feel invulnerable!"); msg_print("You feel vulnerable once more."); msg_print("Your eyes feel very sensitive!"); msg_print("Your eyes feel less sensitive."); msg_print("Your eyes begin to tingle!"); msg_print("Your eyes stop tingling."); msg_print("You feel resistant to acid!"); msg_print("You feel less resistant to acid."); msg_print("You feel resistant to electricity!"); msg_print("You feel less resistant to electricity."); msg_print("You feel resistant to fire!"); msg_print("You feel less resistant to fire."); msg_print("You feel resistant to cold!"); msg_print("You feel less resistant to cold."); msg_print("You feel resistant to poison!"); msg_print("You feel less resistant to poison."); msg_print("You have been stunned."); msg_print("You have been heavily stunned."); msg_print("You have been knocked out."); msg_print("You are no longer stunned."); msg_print("You have been given a graze."); msg_print("You have been given a light cut."); msg_print("You have been given a bad cut."); msg_print("You have been given a nasty cut."); msg_print("You have been given a severe cut."); msg_print("You have been given a deep gash."); msg_print("You have been given a mortal wound."); msg_print("You are no longer bleeding."); msg_print("You are still weak."); msg_print("You are still hungry."); msg_print("You are no longer hungry."); msg_print("You are full!"); msg_print("You have gorged yourself!"); msg_print("You are getting faint from hunger!"); msg_print("You are getting weak from hunger!"); msg_print("You are getting hungry."); msg_print("You are no longer full."); msg_print("You are no longer gorged."); #endif /* 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. */ 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); } } #else #ifdef MACINTOSH static int HACK = 0; #endif /* MACINTOSH */ #endif /* ALLOW_BORG */