/* File: borg7.c */ /* Purpose: High 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" /* * This file handles various high level inventory related goals. * * Problems: * Use "time stamps" (and not "random" checks) for several routines, * including "kill junk" and "wear stuff", and maybe even "free space". * But be careful with the "free space" routine, wear stuff first. * Make sure nothing is "destroyed" if we do not do them every turn. * Consider some special routines in stores (and in the home). * * Hack -- We should perhaps consider wearing "harmless" items into empty * slots when in the dungeon, to allow rings/amulets to be brought back up * to town to be sold. * * We should take account of possible combinations of equipment. This may * be a potentially expensive computation, but could be done occasionally. * It is important to use a "state-less" formula to allow the exchange to * be spread over multiple turns. * * Hack -- We should attempt to only collect non-discounted items, at least * for the "expensive" slots, such as books, since we do not want to lose * value due to stacking. We seem to sell the non-discounted items first, * and to buy the discounted items first, since they are cheap. Oh well, * we may just be stuck with using discounted books. Unless we actually * do correct "combining" in the simulations, and reward free slots. Ick! * * XXX XXX XXX We really need a better "twitchy" function. * * XXX XXX XXX We need a better "flee this level" function * * XXX XXX XXX We need to stockpile possible useful items at home. * * XXX XXX XXX Perhaps we could simply maintain a list of abilities * that we might need at some point, such as the ability to identify, and * simply allow the Borg to "sell" items to the home which satisfy this * desire for "abilities". * * XXX XXX XXX Also, we should probably attempt to track the "best" item * in the home for each equipment slot, using some form of heuristic, and * reward that item based on its power, so that the Borg would always * have a "backup" item in case of disenchantment. * * XXX XXX XXX Also, we could reward equipment based on possible enchantment, * up to the maximal amount available in the home, which would induce item * switching when the item could be enchanted sufficiently. * * Fleeing from fast spell-casters is probably not a very smart idea, nor is * fleeing from fast monsters, nor is attempting to clear a room full of fast * moving breeding monsters, such as lice. */ /* * Hack -- importance of the various "level feelings" * Try to explore the level for at least this many turns */ static s16b value_feeling[] = { 500, 8000, 8000, 6000, 4000, 2000, 1000, 800, 600, 400, 200, 0 }; /* * Determine if an item is "probably" worthless * * This (very heuristic) function is a total hack, designed only to prevent * a very specific annoying situation described below. * * Note that a "cautious" priest (or low level mage/ranger) will leave town * with a few identify scrolls, wander around dungeon level 1 for a few turns, * and use all of the scrolls on leather gloves and broken daggers, and must * then return to town for more scrolls. This may repeat indefinitely. * * The problem is that some characters (priests, mages, rangers) never get an * "average" feeling about items, and have no way to keep track of how long * they have been holding a given item for, so they cannot even attempt to * gain knowledge from the lack of "good" or "cursed" feelings. But they * cannot afford to just identify everything they find by using scrolls of * identify, because, in general, some items are, on average, "icky", and * not even worth the price of a new scroll of identify. * * Even worse, the current algorithm refuses to sell un-identified items, so * the poor character will throw out all his good stuff to make room for crap. * * This function simply examines the item and assumes that certain items are * "icky", which is probably a total hack. Perhaps we could do something like * compare the item to the item we are currently wearing, or perhaps we could * analyze the expected value of the item, or guess at the likelihood that the * item might be a blessed, or something. * * Currently, only characters who do not get "average" feelings are allowed * to decide that something is "icky", others must wait for an "average" * feeling. */ bool borg_item_icky(auto_item *item) { /* Mega-Hack -- allow "icky" items */ if ((auto_class != CLASS_PRIEST) && (auto_class != CLASS_RANGER) && (auto_class != CLASS_MAGE)) return (FALSE); /* Broken dagger/sword, Filthy rag */ if (((item->tval == TV_SWORD) && (item->sval == SV_BROKEN_DAGGER)) || ((item->tval == TV_SWORD) && (item->sval == SV_BROKEN_SWORD)) || ((item->tval == TV_SOFT_ARMOR) && (item->sval == SV_FILTHY_RAG))) { return (TRUE); } /* Dagger, Sling */ if (((item->tval == TV_SWORD) && (item->sval == SV_DAGGER)) || ((item->tval == TV_BOW) && (item->sval == SV_SLING))) { return (TRUE); } /* Cloak, Robe */ if (((item->tval == TV_CLOAK) && (item->sval == SV_CLOAK)) || ((item->tval == TV_SOFT_ARMOR) && (item->sval == SV_ROBE))) { return (TRUE); } /* Leather Gloves */ if ((item->tval == TV_GLOVES) && (item->sval == SV_SET_OF_LEATHER_GLOVES)) { return (TRUE); } /* Hack -- Diggers */ if (item->tval == TV_DIGGING) return (TRUE); /* Assume okay */ return (FALSE); } /* * Use things in a useful, but non-essential, manner */ bool borg_use_things(void) { int i; /* Quaff experience restoration potion */ if (do_fix_exp && borg_quaff_potion(SV_POTION_RESTORE_EXP)) { return (TRUE); } /* Quaff potions of "increase" stat if "needed" */ if (((my_stat_cur[A_STR] < 18+100) && borg_quaff_potion(SV_POTION_INC_STR)) || ((my_stat_cur[A_INT] < 18+100) && borg_quaff_potion(SV_POTION_INC_INT)) || ((my_stat_cur[A_WIS] < 18+100) && borg_quaff_potion(SV_POTION_INC_WIS)) || ((my_stat_cur[A_DEX] < 18+100) && borg_quaff_potion(SV_POTION_INC_DEX)) || ((my_stat_cur[A_CON] < 18+100) && borg_quaff_potion(SV_POTION_INC_CON)) || ((my_stat_cur[A_CHR] < 18+100) && borg_quaff_potion(SV_POTION_INC_CHR))) { return (TRUE); } /* Quaff potions of "restore" stat if needed */ if (((do_fix_stat[A_STR]) && borg_quaff_potion(SV_POTION_RES_STR)) || ((do_fix_stat[A_INT]) && borg_quaff_potion(SV_POTION_RES_INT)) || ((do_fix_stat[A_WIS]) && borg_quaff_potion(SV_POTION_RES_WIS)) || ((do_fix_stat[A_DEX]) && borg_quaff_potion(SV_POTION_RES_DEX)) || ((do_fix_stat[A_CON]) && borg_quaff_potion(SV_POTION_RES_CON)) || ((do_fix_stat[A_CHR]) && borg_quaff_potion(SV_POTION_RES_CHR))) { return (TRUE); } /* Use some items right away */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Process "force" items */ switch (item->tval) { case TV_POTION: /* Check the scroll */ switch (item->sval) { case SV_POTION_ENLIGHTENMENT: /* Never quaff these in town */ if (!auto_depth) break; case SV_POTION_AUGMENTATION: case SV_POTION_EXPERIENCE: /* Try quaffing the potion */ if (borg_quaff_potion(item->sval)) return (TRUE); } break; case TV_SCROLL: /* Hack -- check Blind/Confused */ if (do_blind || do_confused) break; /* XXX XXX XXX Dark */ /* Check the scroll */ switch (item->sval) { case SV_SCROLL_MAPPING: case SV_SCROLL_DETECT_TRAP: case SV_SCROLL_DETECT_DOOR: case SV_SCROLL_ACQUIREMENT: case SV_SCROLL_STAR_ACQUIREMENT: case SV_SCROLL_PROTECTION_FROM_EVIL: /* Never read these in town */ if (!auto_depth) break; /* Try reading the scroll */ if (borg_read_scroll(item->sval)) return (TRUE); } break; } } /* Eat food */ if (do_hungry) { /* Attempt to satisfy hunger */ if (borg_spell(2, 0) || borg_prayer(1, 5) || borg_eat_food(SV_FOOD_RATION)) { return (TRUE); } } /* Nothing to do */ return (FALSE); } /* * Refuel, call lite, detect traps/doors/walls, etc * * Note that we refuel whenever our lite starts to get low. * * Note that we detect traps/doors/walls at least once in each * panel, as soon as possible after entering a new panel. * * Note that we call lite whenever the current grid is dark, and * all the grids touching the current grid diagonally are known * floors, which catches all rooms, including "checkerboard" rooms, * and only occasionally calls lite in corridors, and then only once. * * Note that we also sometimes call lite whenever we are using a * lantern or artifact lite, and when all of the grids in the box * of grids containing the maximal torch-lit region (the 5x5 or 7x7 * region centered at the player) are non-glowing floor grids, and * when at least one of them is known to be "dark". This catches * most of the "probable rooms" before the standard check succeeds. * * We use the special "SELF" messages to "borg_react()" to delay the * processing of "detection" and "call lite" until we know if it has * worked or not. */ bool borg_check_lite(void) { int i, x, y; int q_x, q_y; auto_grid *ag; bool do_lite; bool do_trap; bool do_door; bool do_wall; bool do_lite_aux = FALSE; /* Never in town */ if (!auto_depth) return (FALSE); /* Never when blind or confused or hallucinating */ if (do_blind || do_confused || do_image) return (FALSE); /* XXX XXX XXX Dark */ /* Extract the panel */ q_x = w_x / 33; q_y = w_y / 11; /* Start */ do_trap = FALSE; /* Determine if we need to detect traps */ if (!auto_detect_trap[q_y+0][q_x+0]) do_trap = TRUE; if (!auto_detect_trap[q_y+0][q_x+1]) do_trap = TRUE; if (!auto_detect_trap[q_y+1][q_x+0]) do_trap = TRUE; if (!auto_detect_trap[q_y+1][q_x+1]) do_trap = TRUE; /* Hack -- check traps every few turns anyway */ if (!when_detect_traps || (c_t - when_detect_traps >= 183)) do_trap = TRUE; /* Start */ do_door = FALSE; /* Determine if we need to detect doors */ if (!auto_detect_door[q_y+0][q_x+0]) do_door = TRUE; if (!auto_detect_door[q_y+0][q_x+1]) do_door = TRUE; if (!auto_detect_door[q_y+1][q_x+0]) do_door = TRUE; if (!auto_detect_door[q_y+1][q_x+1]) do_door = TRUE; /* Hack -- check doors every few turns anyway */ if (!when_detect_doors || (c_t - when_detect_doors >= 731)) do_door = TRUE; /* Start */ do_wall = FALSE; /* Determine if we need to detect walls */ if (!auto_detect_wall[q_y+0][q_x+0]) do_wall = TRUE; if (!auto_detect_wall[q_y+0][q_x+1]) do_wall = TRUE; if (!auto_detect_wall[q_y+1][q_x+0]) do_wall = TRUE; if (!auto_detect_wall[q_y+1][q_x+1]) do_wall = TRUE; /* Hack -- check walls every few turns anyway */ if (!when_detect_walls || (c_t - when_detect_walls >= 937)) do_wall = TRUE; /* Hack -- find traps and doors */ if ((do_trap || do_door) && ((!when_detect_traps || (c_t - when_detect_traps >= 5)) || (!when_detect_doors || (c_t - when_detect_doors >= 5)))) { /* Check for traps and doors */ if (borg_zap_rod(SV_ROD_DETECTION) || borg_spell(0, 7) || borg_prayer(5, 1)) { borg_note("# Checking for traps and doors."); borg_react("SELF:both", "SELF:both"); when_detect_traps = c_t; when_detect_doors = c_t; return (TRUE); } } /* Hack -- find traps */ if (do_trap && (!when_detect_traps || (c_t - when_detect_traps >= 7))) { /* Check for traps */ if (borg_read_scroll(SV_SCROLL_DETECT_TRAP) || borg_use_staff(SV_STAFF_DETECT_TRAP) || borg_zap_rod(SV_ROD_DETECT_TRAP) || borg_prayer(0, 5)) { borg_note("# Checking for traps."); borg_react("SELF:trap", "SELF:trap"); when_detect_traps = c_t; return (TRUE); } } /* Hack -- find doors */ if (do_door && (!when_detect_doors || (c_t - when_detect_doors >= 9))) { /* Check for traps */ if (borg_read_scroll(SV_SCROLL_DETECT_DOOR) || borg_use_staff(SV_STAFF_DETECT_DOOR) || borg_zap_rod(SV_ROD_DETECT_DOOR) || borg_prayer(0, 6)) { borg_note("# Checking for doors."); borg_react("SELF:door", "SELF:door"); when_detect_doors = c_t; return (TRUE); } } /* Hack -- find walls */ if (do_wall && (!when_detect_walls || (c_t - when_detect_walls >= 15))) { /* Check for walls */ if (borg_activate_artifact(ART_ELENDIL) || borg_read_scroll(SV_SCROLL_MAPPING) || borg_use_staff(SV_STAFF_MAPPING) || borg_prayer(2, 6)) { borg_note("# Checking for walls."); borg_react("SELF:wall", "SELF:wall"); when_detect_walls = c_t; return (TRUE); } } /* Start */ do_lite = FALSE; /* Get central grid */ ag = &auto_grids[c_y][c_x]; /* Dark central grid */ if (ag->info & BORG_DARK) { /* Assume okay */ do_lite = TRUE; /* Scan diagonal neighbors */ for (i = 4; i < 8; i++) { /* Get location */ x = c_x + ddx_ddd[i]; y = c_y + ddy_ddd[i]; /* Get grid */ ag = &auto_grids[y][x]; /* Location must be known */ if (ag->feat == FEAT_NONE) do_lite = FALSE; /* Location must not be a wall/door */ if (!borg_cave_floor_grid(ag)) do_lite = FALSE; } } /* Hack */ if (!do_lite && (my_cur_lite >= 2) && (c_x >= my_cur_lite) && (c_x < AUTO_MAX_X - my_cur_lite) && (c_y >= my_cur_lite) && (c_y < AUTO_MAX_Y - my_cur_lite) && (rand_int(100) < 90)) { bool f1 = TRUE; bool f2 = FALSE; /* Scan the "local" grids (5x5 or 7x7) */ for (y = c_y - my_cur_lite; y <= c_y + my_cur_lite; y++) { /* Scan the "local" grids (5x5 or 7x7) */ for (x = c_x - my_cur_lite; x <= c_x + my_cur_lite; x++) { /* Get grid */ ag = &auto_grids[y][x]; /* Location must be a floor */ if (!borg_cave_floor_grid(ag)) f1 = FALSE; /* Location must not be glowing */ if (ag->info & BORG_GLOW) f1 = FALSE; /* Notice any known dark grids */ if (ag->info & BORG_DARK) f2 = TRUE; } } /* Sounds good XXX XXX XXX */ if (f1 && f2) do_lite = do_lite_aux = TRUE; } /* Hack -- call lite */ if (do_lite && (!when_call_lite || (c_t - when_call_lite >= 7))) { /* Call light */ if (borg_activate_artifact(ART_GALADRIEL) || borg_zap_rod(SV_ROD_ILLUMINATION) || borg_use_staff(SV_STAFF_LITE) || borg_read_scroll(SV_SCROLL_LIGHT) || borg_spell(0, 3) || borg_prayer(0, 4)) { if (do_lite_aux) borg_note("# Gratuitous illumination"); borg_note("# Illuminating the room"); borg_react("SELF:lite", "SELF:lite"); when_call_lite = c_t; return (TRUE); } } /* Hack -- Wizard Lite */ if (TRUE && (!when_wizard_lite || (c_t - when_wizard_lite >= 1000))) { /* Wizard lite */ if (borg_activate_artifact(ART_THRAIN) || borg_prayer(5, 4)) { borg_note("# Illuminating the dungeon"); /* borg_react("SELF:wizard lite", "SELF:wizard lite"); */ when_wizard_lite = c_t; return (TRUE); } } /* Oops */ return (FALSE); } /* * Enchant armor */ static bool borg_enchant_to_a(void) { int i, b_i = -1; int a, b_a = 99; /* Nothing to enchant */ if (!my_need_enchant_to_a) return (FALSE); /* Need "enchantment" ability */ if (!amt_enchant_to_a) return (FALSE); /* Look for armor that needs enchanting */ for (i = INVEN_BODY; i <= INVEN_FEET; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip non-identified items */ if (!item->able) continue; /* Obtain the bonus */ a = item->to_a; /* Skip "boring" items */ if (a >= 8) continue; /* Find the least enchanted item */ if ((b_i >= 0) && (b_a < a)) continue; /* Save the info */ b_i = i; b_a = a; } /* Nothing */ if (b_i < 0) return (FALSE); /* Enchant it */ if (borg_prayer(7, 4) || borg_read_scroll(SV_SCROLL_ENCHANT_ARMOR)) { /* Choose from equipment */ borg_keypress('/'); /* Choose that item */ borg_keypress(I2A(b_i - INVEN_WIELD)); /* Success */ return (TRUE); } /* Nothing to do */ return (FALSE); } /* * Enchant weapons to hit */ static bool borg_enchant_to_h(void) { int i, b_i = -1; int a, b_a = 99; /* Nothing to enchant */ if (!my_need_enchant_to_h) return (FALSE); /* Need "enchantment" ability */ if (!amt_enchant_to_h) return (FALSE); /* Look for a weapon that needs enchanting */ for (i = INVEN_WIELD; i <= INVEN_BOW; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip non-identified items */ if (!item->able) continue; /* Obtain the bonus */ a = item->to_h; /* Skip "boring" items */ if (a >= 8) continue; /* Find the least enchanted item */ if ((b_i >= 0) && (b_a < a)) continue; /* Save the info */ b_i = i; b_a = a; } /* Nothing */ if (b_i < 0) return (FALSE); /* Enchant it */ if (borg_prayer(7, 3) || borg_read_scroll(SV_SCROLL_ENCHANT_WEAPON_TO_HIT)) { /* Choose from equipment */ borg_keypress('/'); /* Choose that item */ borg_keypress(I2A(b_i - INVEN_WIELD)); /* Success */ return (TRUE); } /* Nothing to do */ return (FALSE); } /* * Enchant weapons */ static bool borg_enchant_to_d(void) { int i, b_i = -1; int a, b_a = 99; /* Nothing to enchant */ if (!my_need_enchant_to_d) return (FALSE); /* Need "enchantment" ability */ if (!amt_enchant_to_d) return (FALSE); /* Look for a weapon that needs enchanting */ for (i = INVEN_WIELD; i <= INVEN_BOW; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip non-identified items */ if (!item->able) continue; /* Obtain the bonus */ a = item->to_d; /* Skip "boring" items */ if (a >= 8) continue; /* Find the least enchanted item */ if ((b_i >= 0) && (b_a < a)) continue; /* Save the info */ b_i = i; b_a = a; } /* Nothing */ if (b_i < 0) return (FALSE); /* Enchant it */ if (borg_prayer(7, 3) || borg_read_scroll(SV_SCROLL_ENCHANT_WEAPON_TO_DAM)) { /* Choose from equipment */ borg_keypress('/'); /* Choose that item */ borg_keypress(I2A(b_i - INVEN_WIELD)); /* Success */ return (TRUE); } /* Nothing to do */ return (FALSE); } /* * Enchant things */ bool borg_enchanting(void) { /* Forbid blind/confused */ if (do_blind || do_confused) return (FALSE); /* XXX XXX XXX Dark */ /* Enchant things */ if (borg_enchant_to_d()) return (TRUE); if (borg_enchant_to_a()) return (TRUE); if (borg_enchant_to_h()) return (TRUE); /* Nope */ return (FALSE); } /* * Recharge things * * XXX XXX XXX Prioritize available items */ bool borg_recharging(void) { int i, b_i = -1; /* Forbid blind/confused */ if (do_blind || do_confused) return (FALSE); /* XXX XXX XXX Dark */ /* Look for an item to recharge */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip non-identified items */ if (!item->able) continue; /* Skip non wands/staffs */ if ((item->tval != TV_STAFF) && (item->tval != TV_WAND)) continue; /* Skip charged items */ if (item->pval) continue; /* Save the info */ b_i = i; } /* Nope */ if (b_i < 0) return (FALSE); /* Attempt to recharge */ if (borg_spell(6, 2) || borg_spell(3, 1) || borg_spell(2, 1) || borg_prayer(7, 1) || borg_read_scroll(SV_SCROLL_RECHARGING)) { auto_item *item = &auto_items[b_i]; /* Message */ borg_note(format("Recharging %s", item->desc)); /* Recharge the item */ borg_keypress(I2A(b_i)); /* Success */ return (TRUE); } /* Nope */ return (FALSE); } /* * Attempt to consume an item */ static bool borg_consume(int i) { auto_item *item = &auto_items[i]; /* Special destruction */ switch (item->tval) { case TV_POTION: /* Check the potion */ switch (item->sval) { case SV_POTION_WATER: case SV_POTION_APPLE_JUICE: case SV_POTION_SLIME_MOLD: case SV_POTION_CURE_LIGHT: case SV_POTION_CURE_SERIOUS: case SV_POTION_CURE_CRITICAL: case SV_POTION_HEALING: case SV_POTION_STAR_HEALING: case SV_POTION_LIFE: case SV_POTION_RES_STR: case SV_POTION_RES_INT: case SV_POTION_RES_WIS: case SV_POTION_RES_DEX: case SV_POTION_RES_CON: case SV_POTION_RES_CHR: case SV_POTION_RESTORE_EXP: case SV_POTION_RESTORE_MANA: case SV_POTION_HEROISM: case SV_POTION_BESERK_STRENGTH: case SV_POTION_RESIST_HEAT: case SV_POTION_RESIST_COLD: case SV_POTION_INFRAVISION: case SV_POTION_DETECT_INVIS: case SV_POTION_SLOW_POISON: case SV_POTION_CURE_POISON: case SV_POTION_SPEED: /* Try quaffing the potion */ if (borg_quaff_potion(item->sval)) return (TRUE); } break; case TV_SCROLL: /* Check the scroll */ switch (item->sval) { case SV_SCROLL_REMOVE_CURSE: case SV_SCROLL_LIGHT: case SV_SCROLL_MONSTER_CONFUSION: case SV_SCROLL_RUNE_OF_PROTECTION: case SV_SCROLL_STAR_REMOVE_CURSE: case SV_SCROLL_DETECT_GOLD: case SV_SCROLL_DETECT_ITEM: case SV_SCROLL_TRAP_DOOR_DESTRUCTION: case SV_SCROLL_SATISFY_HUNGER: case SV_SCROLL_DISPEL_UNDEAD: case SV_SCROLL_BLESSING: case SV_SCROLL_HOLY_CHANT: case SV_SCROLL_HOLY_PRAYER: /* Try reading the scroll */ if (borg_read_scroll(item->sval)) return (TRUE); } break; case TV_FOOD: /* Check the scroll */ switch (item->sval) { case SV_FOOD_CURE_POISON: case SV_FOOD_CURE_BLINDNESS: case SV_FOOD_CURE_PARANOIA: case SV_FOOD_CURE_CONFUSION: case SV_FOOD_CURE_SERIOUS: case SV_FOOD_RESTORE_STR: case SV_FOOD_RESTORE_CON: case SV_FOOD_RESTORING: case SV_FOOD_BISCUIT: case SV_FOOD_JERKY: case SV_FOOD_RATION: case SV_FOOD_SLIME_MOLD: case SV_FOOD_WAYBREAD: case SV_FOOD_PINT_OF_ALE: case SV_FOOD_PINT_OF_WINE: /* Try eating the food (unless Bloated) */ if (!do_full && borg_eat_food(item->sval)) return (TRUE); } break; } /* Nope */ return (FALSE); } /* * Destroy "junk" items */ bool borg_crush_junk(void) { int i; /* Hack -- no need */ if (!auto_do_crush_junk) return (FALSE); /* Destroy actual "junk" items */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip non "worthless" items */ if ((item->tval > TV_CHEST) && (item->value > 0)) continue; /* Hack -- Skip artifacts */ if (item->name1) continue; /* Hack -- skip "artifacts" */ if (streq(item->note, "{special}")) continue; if (streq(item->note, "{terrible}")) continue; /* Message */ borg_note(format("# Junking junk (junk)")); /* Message */ borg_note(format("# Destroying %s.", item->desc)); /* Destroy all items */ borg_keypress('0'); /* Destroy that item */ borg_keypress('k'); borg_keypress(I2A(i)); /* Verify destruction */ /* borg_keypress('y'); */ /* Success */ return (TRUE); } /* Hack -- no need */ auto_do_crush_junk = FALSE; /* Nothing to destroy */ return (FALSE); } /* * Destroy something to make a free inventory slot. * * This function evaluates the possible worlds that result from * the destruction of each inventory slot, and attempts to destroy * that slot which causes the best possible resulting world. * * We attempt to avoid destroying unknown items by "rewarding" the * presence of unknown items by a massively heuristic value. * * If the Borg cannot find something to destroy, which should only * happen if he fills up with artifacts, then he will probably act * rather twitchy for a while. * * This function does not have to be very efficient. */ bool borg_crush_hole(void) { int i, b_i = -1; s32b p, b_p = 0L; bool fix = FALSE; /* Hack -- no need */ if (!auto_do_crush_hole) return (FALSE); /* Do not destroy items unless we need the space */ if (!auto_items[INVEN_PACK-1].iqty) return (FALSE); /* Scan the inventory */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Hack -- skip "artifacts" */ if (item->name1) continue; /* Hack -- skip "artifacts" */ if (streq(item->note, "{special}")) continue; if (streq(item->note, "{terrible}")) continue; /* Save the item */ COPY(&safe_items[i], &auto_items[i], auto_item); /* Destroy the item */ WIPE(&auto_items[i], auto_item); /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ p = borg_power(); /* Restore the item */ COPY(&auto_items[i], &safe_items[i], auto_item); /* Penalize loss of "gold" */ p -= (item->iqty * item->value); /* Hack -- try not to destroy "unaware" items */ if (!item->kind && (item->value > 0)) { /* Hack -- Reward "unaware" items */ switch (item->tval) { case TV_RING: case TV_AMULET: p -= (auto_max_depth * 5000L); break; case TV_ROD: p -= (auto_max_depth * 3000L); break; case TV_STAFF: case TV_WAND: p -= (auto_max_depth * 2000L); break; case TV_SCROLL: case TV_POTION: p -= (auto_max_depth * 500L); break; case TV_FOOD: p -= (auto_max_depth * 10L); break; } } /* Hack -- try not to destroy "unknown" items (unless "icky") */ if (!item->able && !streq(item->note, "{average}") && (item->value > 0) && !borg_item_icky(item)) { /* Reward "unknown" items */ switch (item->tval) { case TV_SHOT: case TV_ARROW: case TV_BOLT: p -= 100L; break; case TV_BOW: p -= 20000L; break; case TV_DIGGING: p -= 10L; break; case TV_HAFTED: case TV_POLEARM: case TV_SWORD: p -= 10000L; break; case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_CLOAK: p -= 15000L; break; case TV_SOFT_ARMOR: case TV_HARD_ARMOR: case TV_DRAG_ARMOR: p -= 15000L; break; case TV_AMULET: case TV_RING: p -= 5000L; break; case TV_STAFF: case TV_WAND: p -= 1000L; break; } } /* Ignore "bad" swaps */ if ((b_i >= 0) && (p < b_p)) continue; /* Maintain the "best" */ b_i = i; b_p = p; } /* Examine the inventory */ if (fix) borg_notice(); /* Attempt to destroy it */ if (b_i >= 0) { auto_item *item = &auto_items[b_i]; /* Debug */ borg_note(format("# Junking %ld gold (full)", my_power - b_p)); /* Try to consume the junk */ if (borg_consume(b_i)) return (TRUE); /* Message */ borg_note(format("# Destroying %s.", item->desc)); /* Destroy all items */ borg_keypress('0'); /* Destroy that item */ borg_keypress('k'); borg_keypress(I2A(b_i)); /* Verify destruction */ /* borg_keypress('y'); */ /* Success */ return (TRUE); } /* Hack -- no need */ auto_do_crush_hole = FALSE; /* Paranoia */ return (FALSE); } /* * Destroy "junk" when slow (in the dungeon). * * We penalize the loss of both power and monetary value, and reward * the loss of weight that may be slowing us down. The weight loss * is worth one gold per tenth of a pound. This causes things like * lanterns and chests and spikes to be considered "annoying". */ bool borg_crush_slow(void) { int i, b_i = -1; s32b p, b_p = 0L; s32b temp; s32b greed; bool fix = FALSE; /* Hack -- no need */ if (!auto_do_crush_slow) return (FALSE); /* Hack -- never in town */ if (!auto_depth) return (FALSE); /* Do not crush items unless we are slow */ if (auto_speed >= 110) return (FALSE); /* Calculate "greed" factor */ greed = (auto_gold / 100L) + 100L; /* Minimal greed */ if (greed > 1000L) greed = 1000L; /* Scan for junk */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip "good" unknown items (unless "icky") */ if (!item->able && !streq(item->note, "{average}") && (item->value > 0) && !borg_item_icky(item)) continue; /* Hack -- Skip artifacts */ if (item->name1) continue; /* Save the item */ COPY(&safe_items[i], &auto_items[i], auto_item); /* Destroy one of the items */ auto_items[i].iqty--; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ p = borg_power(); /* Restore the item */ COPY(&auto_items[i], &safe_items[i], auto_item); /* Obtain the base price */ temp = ((item->value < 30000L) ? item->value : 30000L); /* Hack -- ignore very cheap items */ if (temp < greed) temp = 0L; /* Penalize */ p -= temp; /* Obtain the base weight */ temp = item->weight; /* Reward */ p += temp; /* Ignore "bad" swaps */ if ((b_i >= 0) && (p < b_p)) continue; /* Maintain the "best" */ b_i = i; b_p = p; } /* Examine the inventory */ if (fix) borg_notice(); /* Destroy "useless" things */ if ((b_i >= 0) && (b_p >= my_power)) { auto_item *item = &auto_items[b_i]; /* Message */ borg_note(format("# Junking %ld gold (slow)", my_power - b_p)); /* Attempt to consume it */ if (borg_consume(b_i)) return (TRUE); /* Message */ borg_note(format("# Destroying %s.", item->desc)); /* Destroy one item */ borg_keypress('0'); borg_keypress('1'); /* Destroy that item */ borg_keypress('k'); borg_keypress(I2A(b_i)); /* Verify destruction */ /* borg_keypress('y'); */ } /* Hack -- no need */ auto_do_crush_slow = FALSE; /* Nothing to destroy */ return (FALSE); } /* * Identify items if possible * * Note that "borg_parse()" will "cancel" the identification if it * detects a "You failed..." message. This is VERY important!!! * Otherwise the "identify" might induce bizarre actions by sending * the "index" of an item as a command. * * Hack -- recover from mind blanking by re-identifying the equipment. * * We instantly identify items known to be "good" (or "terrible"). * * We identify most un-aware items as soon as possible. * * We identify most un-known items as soon as possible. * * We play games with items that get "feelings" to try and wait for * "sensing" to take place if possible. * * XXX XXX XXX Make sure not to sell "non-aware" items, unless * we are really sure we want to lose them. For example, we should * wait for feelings on (non-icky) wearable items or else make sure * that we identify them before we try and sell them. * * Mega-Hack -- the whole "sometimes identify things" code is a total * hack. Slightly less bizarre would be some form of "occasionally, * pick a random item and identify it if necessary", which might lower * the preference for identifying items that appear early in the pack. * Also, preventing inventory motion would allow proper time-stamping. */ bool borg_test_stuff(void) { int i, b_i = -1; s32b v, b_v = -1; /* Look for an item to identify (equipment) */ for (i = INVEN_WIELD; i <= INVEN_FEET; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip known items */ if (item->able) continue; /* Hack -- never identify "average" things */ /* if (streq(item->note, "{average}")) continue; */ /* Get the value */ v = item->value + 100000L; /* Track the best */ if (v < b_v) continue; /* Track it */ b_i = i; b_v = v; } /* Look for an item to identify (inventory) */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip known items */ if (item->able) continue; /* Assume nothing */ v = 0; /* Identify "good" (and "terrible") items */ if (streq(item->note, "{good}")) v = item->value + 10000L; else if (streq(item->note, "{excellent}")) v = item->value + 20000L; else if (streq(item->note, "{special}")) v = item->value + 50000L; else if (streq(item->note, "{terrible}")) v = item->value + 50000L; /* Nothing */ if (!v) continue; /* Track the best */ if (v < b_v) continue; /* Track it */ b_i = i; b_v = v; } /* Look for an item to identify (inventory) */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip known items */ if (item->able) continue; /* Hack -- never identify "average" things */ if (streq(item->note, "{average}")) continue; /* Hack -- assume no value */ v = 0; /* Hack -- reward "unaware" items */ if (!item->kind) { /* Analyze the type */ switch (item->tval) { case TV_RING: case TV_AMULET: /* Hack -- reward depth */ v += (auto_max_depth * 5000L); break; case TV_ROD: /* Hack -- reward depth */ v += (auto_max_depth * 3000L); break; case TV_WAND: case TV_STAFF: /* Hack -- reward depth */ v += (auto_max_depth * 2000L); break; case TV_POTION: case TV_SCROLL: /* Hack -- boring levels */ if (auto_max_depth < 5) break; /* Hack -- reward depth */ v += (auto_max_depth * 500L); break; case TV_FOOD: /* Hack -- reward depth */ v += (auto_max_depth * 10L); break; } } /* Analyze the type */ switch (item->tval) { case TV_CHEST: /* Hack -- Always identify chests */ v = item->value; break; case TV_WAND: case TV_STAFF: /* Hack -- Always identify (get charges) */ v = item->value; break; case TV_RING: case TV_AMULET: /* Hack -- Always identify (get information) */ v = item->value; break; case TV_LITE: /* Hack -- Always identify (get artifact info) */ v = item->value; break; case TV_SHOT: case TV_ARROW: case TV_BOLT: case TV_BOW: case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_CLOAK: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: case TV_DRAG_ARMOR: /* Mega-Hack -- use identify spell/prayer */ if (borg_spell_legal(2, 4) || borg_prayer_legal(5, 2)) { v = item->value; } /* Mega-Hack -- mages get bored */ if ((auto_class == 1) && (rand_int(1000) < auto_level)) { /* Mega-Hack -- ignore "icky" items */ if (!borg_item_icky(item)) v = item->value; } /* Mega-Hack -- rangers get bored */ if ((auto_class == 4) && (rand_int(3000) < auto_level)) { /* Mega-Hack -- ignore "icky" items */ if (!borg_item_icky(item)) v = item->value; } /* Mega-Hack -- priests get bored */ if ((auto_class == 2) && (rand_int(5000) < auto_level)) { /* Mega-Hack -- ignore "icky" items */ if (!borg_item_icky(item)) v = item->value; } break; } /* Ignore */ if (!v) continue; /* Track the best */ if (v < b_v) continue; /* Track it */ b_i = i; b_v = v; } /* Found something */ if (b_i >= 0) { auto_item *item = &auto_items[b_i]; /* Use a Spell/Prayer/Rod/Staff/Scroll of Identify */ if (borg_spell(2, 4) || borg_prayer(5, 2) || borg_zap_rod(SV_ROD_IDENTIFY) || borg_use_staff(SV_STAFF_IDENTIFY) || borg_read_scroll(SV_SCROLL_IDENTIFY)) { /* Log -- may be cancelled */ borg_note(format("# Identifying %s.", item->desc)); /* Equipment */ if (b_i >= INVEN_WIELD) { /* Select the equipment */ borg_keypress('/'); /* Select the item */ borg_keypress(I2A(b_i - INVEN_WIELD)); } /* Inventory */ else { /* Select the item */ borg_keypress(I2A(b_i)); } /* Success */ return (TRUE); } } /* Nothing to do */ return (FALSE); } /* * Attempt to take off useless equipment */ bool borg_takeoff_stuff(void) { int hole = INVEN_PACK - 1; int i, b_i = -1; s32b v, b_v = 0L; bool fix = FALSE; /* Require an empty slot */ if (auto_items[hole].iqty) return (FALSE); /* Scan equipment */ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) { auto_item *item = &auto_items[i]; /* Skip empty slots */ if (!item->iqty) continue; /* Save the hole */ COPY(&safe_items[hole], &auto_items[hole], auto_item); /* Save the item */ COPY(&safe_items[i], &auto_items[i], auto_item); /* Take off the item */ COPY(&auto_items[hole], &safe_items[i], auto_item); /* Erase the item */ WIPE(&auto_items[i], auto_item); /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ v = borg_power(); /* Restore the item */ COPY(&auto_items[i], &safe_items[i], auto_item); /* Restore the hole */ COPY(&auto_items[hole], &safe_items[hole], auto_item); /* Track best */ if ((b_i >= 0) && (b_v >= v)) continue; /* Track best */ b_i = i; b_v = v; } /* Examine the inventory */ if (fix) borg_notice(); /* Prepare to "swap" if needed */ if ((b_i >= 0) && (b_v >= my_power)) { auto_item *item = &auto_items[b_i]; /* Log */ borg_note(format("# Taking off %s.", item->desc)); /* Take off item */ borg_keypress('t'); borg_keypress(I2A(b_i - INVEN_WIELD)); /* Success */ return (TRUE); } /* Nope */ return (FALSE); } /* * This function is responsible for making sure that, if possible, * the "best" ring we have is always on the "right" (tight) finger, * so that the other functions, such as "borg_best_stuff()", do not * have to think about the "tight" ring, but instead, can just assume * that the "right" ring is "good for us" and should never be removed. * * In general, this will mean that our "best" ring of speed will end * up on the "right" finger, if we have one, or a ring of free action, * or a ring of see invisible, or some other "useful" ring. * * This routine is only called in shops, to allow us to "safely" play * the ring shuffling game, since this routine may take several steps, * and we must be able to do them all without being attacked. */ bool borg_swap_rings(void) { int hole = INVEN_PACK - 1; int icky = INVEN_PACK - 2; s32b v1, v2; bool fix = FALSE; /*** Check conditions ***/ /* Require an empty slot */ if (auto_items[hole].iqty) return (FALSE); /*** Remove naked "loose" rings ***/ /* Remove any naked loose ring */ if (auto_items[INVEN_LEFT].iqty && !auto_items[INVEN_RIGHT].iqty) { /* Log */ borg_note("# Taking off naked loose ring."); /* Remove it */ borg_keypress('t'); borg_keypress(I2A(INVEN_LEFT - INVEN_WIELD)); /* Success */ return (TRUE); } /*** Check conditions ***/ /* Require another empty slot */ if (auto_items[icky].iqty) return (FALSE); /* Require "tight" ring */ if (!auto_items[INVEN_RIGHT].iqty) return (FALSE); /*** Remove nasty "tight" rings ***/ /* Save the hole */ COPY(&safe_items[hole], &auto_items[hole], auto_item); /* Save the ring */ COPY(&safe_items[INVEN_LEFT], &auto_items[INVEN_LEFT], auto_item); /* Take off the ring */ COPY(&auto_items[hole], &auto_items[INVEN_LEFT], auto_item); /* Erase left ring */ WIPE(&auto_items[INVEN_LEFT], auto_item); /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ v1 = borg_power(); /* Restore the ring */ COPY(&auto_items[INVEN_LEFT], &safe_items[INVEN_LEFT], auto_item); /* Restore the hole */ COPY(&auto_items[hole], &safe_items[hole], auto_item); /*** Consider taking off the "right" ring ***/ /* Save the hole */ COPY(&safe_items[hole], &auto_items[hole], auto_item); /* Save the ring */ COPY(&safe_items[INVEN_RIGHT], &auto_items[INVEN_RIGHT], auto_item); /* Take off the ring */ COPY(&auto_items[hole], &auto_items[INVEN_RIGHT], auto_item); /* Erase left ring */ WIPE(&auto_items[INVEN_RIGHT], auto_item); /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ v2 = borg_power(); /* Restore the ring */ COPY(&auto_items[INVEN_RIGHT], &safe_items[INVEN_RIGHT], auto_item); /* Restore the hole */ COPY(&auto_items[hole], &safe_items[hole], auto_item); /*** Swap rings if necessary ***/ /* Examine the inventory */ if (fix) borg_notice(); /* Remove "useless" ring */ if (v2 > v1) { /* Log */ borg_note("# Taking off nasty tight ring."); /* Take it off */ borg_keypress('t'); borg_keypress(I2A(INVEN_RIGHT - INVEN_WIELD)); /* Success */ return (TRUE); } /* Nope */ return (FALSE); } /* * Place our "best" ring on the "tight" finger if needed * * This function is adopted from "borg_wear_stuff()" * * Basically, we evaluate the world in which each ring is added * to the current set of equipment, and we wear the ring, if any, * that gives us the most "power". * * The "borg_swap_rings()" code above occasionally allows us to remove * both rings, at which point this function will place the "best" ring * on the "tight" finger, and then the "borg_best_stuff()" function will * allow us to put on our second "best" ring on the "loose" finger. * * This function should only be used when a ring finger is empty. */ bool borg_wear_rings(void) { int slot; s32b p, b_p = 0L; int i, b_i = -1; auto_item *item; bool fix = FALSE; /* Require no rings */ if (auto_items[INVEN_LEFT].iqty) return (FALSE); if (auto_items[INVEN_RIGHT].iqty) return (FALSE); /* Scan inventory */ for (i = 0; i < INVEN_PACK; i++) { item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Require "aware" */ if (!item->kind) continue; /* Require "known" (or average) */ if (!item->able && !streq(item->note, "{average}")) continue; /* Hack -- ignore "worthless" items */ if (!item->value) continue; /* Where does it go */ slot = borg_wield_slot(item); /* Only process "rings" */ if (slot != INVEN_LEFT) continue; /* Save the old item (empty) */ COPY(&safe_items[slot], &auto_items[slot], auto_item); /* Save the new item */ COPY(&safe_items[i], &auto_items[i], auto_item); /* Wear new item */ COPY(&auto_items[slot], &safe_items[i], auto_item); /* Only a single item */ auto_items[slot].iqty = 1; /* Reduce the inventory quantity by one */ auto_items[i].iqty--; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ p = borg_power(); /* Restore the old item (empty) */ COPY(&auto_items[slot], &safe_items[slot], auto_item); /* Restore the new item */ COPY(&auto_items[i], &safe_items[i], auto_item); /* Ignore "bad" swaps */ if ((b_i >= 0) && (p < b_p)) continue; /* Maintain the "best" */ b_i = i; b_p = p; } /* Restore bonuses */ if (fix) borg_notice(); /* No item */ if ((b_i >= 0) && (b_p > my_power)) { /* Get the item */ item = &auto_items[b_i]; /* Log */ borg_note("# Putting on best tight ring."); /* Log */ borg_note(format("# Wearing %s.", item->desc)); /* Wear it */ borg_keypress('w'); borg_keypress(I2A(b_i)); /* Did something */ return (TRUE); } /* Nope */ return (FALSE); } /* * Wear useful equipment. * * Look through the inventory for equipment that is better than * the current equipment, and wear it, in an optimal order. * * Basically, we evaluate the world both with the current set of * equipment, and in the alternate world in which various items * are used instead of the items they would replace, and we take * one step towards the world in which we have the most "power". * * Although a player can actually wear two rings, we pretend that only * the "loose" ring can be removed, which is the semantics induced by * the "wear" command. * * The "borg_swap_rings()" code above occasionally allows us to remove * both rings, at which point this function will replace the "best" ring * on the "tight" finger, and the second "best" ring on the "loose" finger. */ bool borg_wear_stuff(void) { int hole = INVEN_PACK - 1; int slot; s32b p, b_p = 0L; int i, b_i = -1; auto_item *item; bool fix = FALSE; /* Require an empty slot */ if (auto_items[hole].iqty) return (FALSE); /* Scan inventory */ for (i = 0; i < INVEN_PACK; i++) { item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Require "aware" */ if (!item->kind) continue; /* Require "known" (or average, good, etc) */ if (!item->able && !streq(item->note, "{average}") && !streq(item->note, "{good}") && !streq(item->note, "{excellent}") && !streq(item->note, "{special}")) continue; /* Hack -- ignore "worthless" items */ if (!item->value) continue; /* Where does it go */ slot = borg_wield_slot(item); /* Cannot wear this item */ if (slot < 0) continue; /* Save the old item */ COPY(&safe_items[slot], &auto_items[slot], auto_item); /* Save the new item */ COPY(&safe_items[i], &auto_items[i], auto_item); /* Save the hole */ COPY(&safe_items[hole], &auto_items[hole], auto_item); /* Take off old item */ COPY(&auto_items[hole], &safe_items[slot], auto_item); /* Wear new item */ COPY(&auto_items[slot], &safe_items[i], auto_item); /* Only a single item */ auto_items[slot].iqty = 1; /* Reduce the inventory quantity by one */ auto_items[i].iqty--; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ p = borg_power(); /* Restore the old item */ COPY(&auto_items[slot], &safe_items[slot], auto_item); /* Restore the new item */ COPY(&auto_items[i], &safe_items[i], auto_item); /* Restore the hole */ COPY(&auto_items[hole], &safe_items[hole], auto_item); /* Ignore "bad" swaps */ if ((b_i >= 0) && (p < b_p)) continue; /* XXX XXX XXX Consider if slot is empty */ /* Hack -- Ignore "equal" swaps */ if ((b_i >= 0) && (p == b_p)) continue; /* Maintain the "best" */ b_i = i; b_p = p; } /* Restore bonuses */ if (fix) borg_notice(); /* No item */ if ((b_i >= 0) && (b_p > my_power)) { /* Get the item */ item = &auto_items[b_i]; /* Log */ borg_note(format("# Wearing %s.", item->desc)); /* Wear it */ borg_keypress('w'); borg_keypress(I2A(b_i)); /* Did something */ return (TRUE); } /* Nope */ return (FALSE); } /* * Hack -- order of the slots * * XXX XXX XXX Note that we ignore the "tight" ring, and we * assume that we will always be wearing our "best" ring on * our "right" (tight) finger, and if we are not, then the * "borg_swap_rings()" function will remove both the rings, * which will induce the "borg_best_stuff()" function to put * the rings back on in the "optimal" order. */ static byte borg_best_stuff_order[] = { INVEN_BOW, INVEN_WIELD, INVEN_BODY, INVEN_OUTER, INVEN_ARM, INVEN_HEAD, INVEN_HANDS, INVEN_FEET, INVEN_LITE, INVEN_NECK, INVEN_LEFT, 255 }; /* * Helper function (see below) */ static void borg_best_stuff_aux(int n, byte *test, byte *best, s32b *vp) { int i; int slot; /* Extract the slot */ slot = borg_best_stuff_order[n]; /* All done */ if (slot == 255) { s32b p; /* Examine */ borg_notice(); /* Evaluate */ p = borg_power(); /* Track best */ if (p > *vp) { /* Save the results */ for (i = 0; i < n; i++) best[i] = test[i]; /* Use it */ *vp = p; } /* Success */ return; } /* Note the attempt */ test[n] = slot; /* Evaluate the default item */ borg_best_stuff_aux(n + 1, test, best, vp); /* Try other possible objects */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Require "aware" */ if (!item->kind) continue; /* Require "known" (or average, good, etc) */ if (!item->able && !streq(item->note, "{average}") && !streq(item->note, "{good}") && !streq(item->note, "{excellent}") && !streq(item->note, "{special}")) continue; /* Hack -- ignore "worthless" items */ if (!item->value) continue; /* Make sure it goes in this slot */ if (slot != borg_wield_slot(item)) continue; /* Take off old item */ COPY(&auto_items[i], &safe_items[slot], auto_item); /* Wear the new item */ COPY(&auto_items[slot], &safe_items[i], auto_item); /* Note the attempt */ test[n] = i; /* Evaluate the possible item */ borg_best_stuff_aux(n + 1, test, best, vp); /* Restore equipment */ COPY(&auto_items[slot], &safe_items[slot], auto_item); /* Restore inventory */ COPY(&auto_items[i], &safe_items[i], auto_item); } } /* * Attempt to instantiate the *best* possible equipment. */ bool borg_best_stuff(void) { int hole = INVEN_PACK - 1; int slot; int k; int n = 0; s32b value; int i, b_i = -1; s32b p, b_p = 0L; byte test[12]; byte best[12]; auto_item *item; bool fix = FALSE; /* Require an empty slot */ if (auto_items[hole].iqty) return (FALSE); /* Hack -- Initialize */ for (k = 0; k < 12; k++) { /* Initialize */ best[k] = test[k] = 255; } /* Hack -- Copy all the slots */ for (i = 0; i < INVEN_TOTAL; i++) { /* Save the item */ COPY(&safe_items[i], &auto_items[i], auto_item); } /* Evaluate the inventory */ value = my_power; /* Determine the best possible equipment */ (void)borg_best_stuff_aux(0, test, best, &value); /* Restore bonuses */ borg_notice(); /* Find "easiest" step */ for (k = 0; k < 12; k++) { /* Get choice */ i = best[k]; /* Ignore non-changes */ if (i >= INVEN_WIELD) continue; /* Count changes */ n++; /* Access the item */ item = &auto_items[i]; /* Access the slot */ slot = borg_wield_slot(item); /* Save the old item */ COPY(&safe_items[slot], &auto_items[slot], auto_item); /* Save the new item */ COPY(&safe_items[i], &auto_items[i], auto_item); /* Save the hole */ COPY(&safe_items[hole], &auto_items[hole], auto_item); /* Take off old item */ COPY(&auto_items[hole], &safe_items[slot], auto_item); /* Wear new item */ COPY(&auto_items[slot], &safe_items[i], auto_item); /* Only a single item */ auto_items[slot].iqty = 1; /* Reduce the inventory quantity by one */ auto_items[i].iqty--; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ p = borg_power(); /* Restore the old item */ COPY(&auto_items[slot], &safe_items[slot], auto_item); /* Restore the new item */ COPY(&auto_items[i], &safe_items[i], auto_item); /* Restore the hole */ COPY(&auto_items[hole], &safe_items[hole], auto_item); /* Track the "best" change */ if ((b_i >= 0) && (p < b_p)) continue; /* Maintain the "best" */ b_i = i; b_p = p; } /* Restore bonuses */ if (fix) borg_notice(); /* Start changing */ if (b_i >= 0) { /* Get the item */ auto_item *item = &auto_items[b_i]; /* Log */ borg_note(format("# Besting %s (1/%d).", item->desc, n)); /* Wear it */ borg_keypress('w'); borg_keypress(I2A(b_i)); /* Did something */ return (TRUE); } /* Nope */ return (FALSE); } /* * Study and/or Test spells/prayers */ bool borg_play_magic(bool bored) { int book, what; int i, b_i = -1; int j, b_j = -1; int r, b_r = -1; /* Hack -- must use magic or prayers */ if (!mb_ptr->spell_book) return (FALSE); /* Hack -- blind/confused */ if (do_blind || do_confused) return (FALSE); /* XXX XXX XXX Dark */ /* Check each book (backwards) */ for (book = 9 - 1; book >= 0; book--) { /* Look for the book */ i = auto_book[book]; /* No such book */ if (i < 0) continue; /* Check each spells */ for (what = 9 - 1; what >= 0; what--) { auto_magic *as = &auto_magics[book][what]; /* Require "learnable" status */ if (as->status != BORG_MAGIC_OKAY) continue; /* Obtain "index" */ j = what; /* Obtain "rating" */ r = as->rating; /* Skip "boring" spells/prayers */ if (!bored && (r <= 50)) continue; /* Skip "icky" spells/prayers */ if (r <= 0) continue; /* Skip "worse" spells/prayers */ if (r <= b_r) continue; /* Track it */ b_i = i; b_j = j; b_r = r; } } /* Study */ if (do_study && (b_r > 0)) { auto_magic *as = &auto_magics[b_i][b_j]; /* Debugging Info */ borg_note(format("# Studying spell/prayer %s.", as->name)); /* Learn the spell */ borg_keypress('G'); /* Specify the book */ borg_keypress(I2A(b_i)); /* Specify the spell (but not the prayer) */ if (mb_ptr->spell_book == TV_MAGIC_BOOK) { /* Specify the spell */ borg_keypress(I2A(b_j)); } /* Success */ return (TRUE); } /* Hack -- only in town */ if (auto_depth) return (FALSE); /* Hack -- only when bored */ if (!bored) return (FALSE); /* Check each book (backwards) */ for (book = 9 - 1; book >= 0; book--) { /* Look for the book */ i = auto_book[book]; /* No such book */ if (i < 0) continue; /* Check every spell (backwards) */ for (what = 9 - 1; what >= 0; what--) { auto_magic *as = &auto_magics[book][what]; /* Only try "untried" spells/prayers */ if (as->status != BORG_MAGIC_TEST) continue; /* Ignore "bizarre" spells/prayers */ if (as->method == BORG_MAGIC_OBJ) continue; if (as->method == BORG_MAGIC_WHO) continue; /* Note */ borg_note("# Testing untried spell/prayer"); /* Hack -- Use spell or prayer */ if (borg_spell(book, what) || borg_prayer(book, what)) { /* Hack -- Allow attack spells */ if (as->method == BORG_MAGIC_AIM) { /* Hack -- target self */ borg_keypress('*'); borg_keypress('p'); borg_keypress('t'); } /* Success */ return (TRUE); } } } /* Nope */ return (FALSE); } /* * Count the number of items worth "selling" * * This determines the choice of stairs. * * XXX XXX XXX Total hack, by the way... */ static int borg_count_sell(void) { int i, k = 0; s32b price; s32b greed; /* Calculate "greed" factor */ greed = (auto_gold / 100L) + 100L; /* Minimal greed */ if (greed > 1000L) greed = 1000L; /* Count "sellable" items */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip "crappy" items */ if (item->value <= 0) continue; /* Obtain the base price */ price = ((item->value < 30000L) ? item->value : 30000L); /* Skip cheap "known" (or "average") items */ if ((price * item->iqty < greed) && (item->able || streq(item->note, "{average}"))) continue; /* Count remaining items */ k++; } /* Result */ return (k); } /* * Leave the level if necessary (or bored) */ bool borg_leave_level(bool bored) { int i, k, g = 0; /* Hack -- waiting for "recall" */ if (goal_recalling) return (FALSE); /* Hack -- Note level completion */ if (bored && borg_prepared(auto_depth - 1)) { /* Clear fear up to next level */ for (i = 0; i <= auto_depth + 1; i++) { /* Remove fear */ auto_fear_depth[i] = FALSE; } } /* Town */ if (!auto_depth) { /* Cancel rising */ goal_rising = FALSE; /* Wait until bored */ if (!bored) return (FALSE); /* Hack -- Recall into dungeon */ if ((auto_max_depth >= 5) && (amt_recall > 4) && borg_prepared(auto_max_depth - 1) && borg_recall()) { /* Note */ borg_note("# Recalling into dungeon (for fun)..."); /* Give it a shot */ return (TRUE); } /* Take next stairs */ stair_more = TRUE; /* Attempt to use those stairs */ if (borg_flow_stair_more(GOAL_BORE)) return (TRUE); /* Oops */ return (FALSE); } /* Count sellable items */ k = borg_count_sell(); /* Dive when bored */ if (bored) g = 1; /* Hack -- Power-dive downwards when able */ if (auto_level > auto_depth * 2 + 2) g = 1; /* Do not enter dangerous depths */ if (g && !borg_prepared(auto_depth + 1)) g = 0; /* Do not dive when "full" of items */ if (g && (k >= 18)) g = 0; /* Do not dive when drained */ if (g && do_fix_exp) g = 0; /* Hack -- Power-dive upwards when needed */ if (!borg_prepared(auto_depth)) g = -1; /* Hack -- Stay on each level for a minimal amount of time */ if (g && (c_t - auto_began < value_feeling[auto_feeling])) g = 0; /* Return to town when bored and unable to dive */ if (bored && !borg_prepared(auto_depth + 1)) goal_rising = TRUE; /* Return to town to sell stuff */ if (bored && (k >= 18)) goal_rising = TRUE; /* Return to town when level drained */ if (do_fix_lev) goal_rising = TRUE; /* Return to town to restore experience */ if (bored && do_fix_exp) goal_rising = TRUE; /* Return to town */ if (goal_rising) g = -1; /* Mega-Hack -- spend time on the first level to rotate shops */ if ((auto_depth == 1) && (c_t - auto_began < 100) && (g < 0)) g = 0; /* Use random stairs when really bored */ if (bored && (c_t - auto_began >= 5000)) { /* Note */ borg_note("# Choosing random stairs."); /* Use random stairs */ g = ((rand_int(100) < 50) ? -1 : 1); } /* Go Up */ if (g < 0) { /* Take next stairs */ stair_less = TRUE; /* Hack -- recall */ if (goal_rising && (auto_depth >= 5) && (amt_recall > 3) && borg_recall()) { borg_note("# Recalling to town (for fun)"); return (TRUE); } /* Attempt to use stairs */ if (borg_flow_stair_less(GOAL_BORE)) return (TRUE); /* Cannot find any stairs */ if (goal_rising && bored) { if (borg_recall()) { borg_note("# Recalling to town (no stairs)"); return (TRUE); } } } /* Go Down */ if (g > 0) { /* Take next stairs */ stair_more = TRUE; /* Attempt to use those stairs */ if (borg_flow_stair_more(GOAL_BORE)) return (TRUE); } /* Failure */ return (FALSE); } /* * Initialize this file */ void borg_init_7(void) { /* Nothing */ } #else #ifdef MACINTOSH static int HACK = 0; #endif /* MACINTOSH */ #endif /* ALLOW_BORG */