/* File: borg8.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" #include "borg8.h" byte *test; byte *best; s32b *b_home_power; /* * Determine if an item can "absorb" a second item * * See "object_absorb()" for the actual "absorption" code. * * If permitted, we allow wands/staffs (if they are known to have equal * charges) and rods (if fully charged) to combine. * * Note that rods/staffs/wands are then unstacked when they are used. * * If permitted, we allow weapons/armor to stack, if they both known. * * Food, potions, scrolls, and "easy know" items always stack. * * Chests never stack (for various reasons). * * We do NOT allow activatable items (artifacts or dragon scale mail) * to stack, to keep the "activation" code clean. Artifacts may stack, * but only with another identical artifact (which does not exist). * * Ego items may stack as long as they have the same ego-item type. * This is primarily to allow ego-missiles to stack. */ static bool borg_object_similar(auto_item *o_ptr, auto_item *j_ptr) { /* NOTE: This assumes the giving of one item at a time */ int total = o_ptr->iqty + 1; /* Require identical object types */ if (o_ptr->kind != j_ptr->kind) return (0); /* Analyze the items */ switch (o_ptr->tval) { /* Chests */ case TV_CHEST: { /* Never okay */ return (0); } /* Food and Potions and Scrolls */ case TV_FOOD: case TV_POTION: case TV_SCROLL: { /* Assume okay */ break; } /* Staffs and Wands */ case TV_STAFF: case TV_WAND: { /* Require knowledge */ if ((!o_ptr->able) || (!j_ptr->able)) return (0); /* Fall through */ } /* Staffs and Wands and Rods */ case TV_ROD: { /* Require permission */ if (!stack_allow_wands) return (0); /* Require identical charges */ if (o_ptr->pval != j_ptr->pval) return (0); /* Probably okay */ break; } /* Weapons and Armor */ 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: { /* Require permission */ if (!stack_allow_items) return (0); /* XXX XXX XXX Require identical "sense" status */ /* if ((o_ptr->ident & ID_SENSE) != */ /* (j_ptr->ident & ID_SENSE)) return (0); */ /* Fall through */ } /* Rings, Amulets, Lites */ case TV_RING: case TV_AMULET: case TV_LITE: { /* Require full knowledge of both items */ if ((!o_ptr->able) || (!j_ptr->able)) return (0); /* Fall through */ } /* Missiles */ case TV_BOLT: case TV_ARROW: case TV_SHOT: { /* Require identical "bonuses" */ if (o_ptr->to_h != j_ptr->to_h) return (FALSE); if (o_ptr->to_d != j_ptr->to_d) return (FALSE); if (o_ptr->to_a != j_ptr->to_a) return (FALSE); /* Require identical "pval" code */ if (o_ptr->pval != j_ptr->pval) return (FALSE); /* Require identical "artifact" names */ if (o_ptr->name1 != j_ptr->name1) return (FALSE); /* Require identical "ego-item" names */ if (o_ptr->name2 != j_ptr->name2) return (FALSE); /* Hack -- Never stack "powerful" items */ if (o_ptr->flags1 || j_ptr->flags1) return (FALSE); if (o_ptr->flags2 || j_ptr->flags2) return (FALSE); if (o_ptr->flags3 || j_ptr->flags3) return (FALSE); /* Hack -- Never stack recharging items */ if (o_ptr->timeout || j_ptr->timeout) return (FALSE); /* Require identical "values" */ if (o_ptr->ac != j_ptr->ac) return (FALSE); if (o_ptr->dd != j_ptr->dd) return (FALSE); if (o_ptr->ds != j_ptr->ds) return (FALSE); /* Probably okay */ break; } /* Various */ default: { /* Require knowledge */ if ((!o_ptr->able) || (!j_ptr->able)) return (0); /* Probably okay */ break; } } /* Hack -- Require identical "broken" status */ if ((o_ptr->fully_identified) != (j_ptr->fully_identified)) return (0); /* The stuff with 'note' is not right but it is close. I think it */ /* has him assuming that he can't stack sometimes when he can. This */ /* is alright, it just causes him to take a bit more time to do */ /* some exchanges. */ /* Hack -- require semi-matching "inscriptions" */ if (o_ptr->note[0] && j_ptr->note[0] && (!streq(o_ptr->note, j_ptr->note))) return (0); /* Hack -- normally require matching "inscriptions" */ if (!stack_force_notes && (!streq(o_ptr->note, j_ptr->note))) return (0); /* Hack -- normally require matching "discounts" */ if (!stack_force_costs && (o_ptr->discount != j_ptr->discount)) return (0); /* Maximal "stacking" limit */ if (total >= MAX_STACK_SIZE) return (0); /* They match, so they must be similar */ return (TRUE); } /* * This file handles the highest level goals, and store interaction. * * Store interaction strategy * * (1) Sell items to the home (for later use) ** optimize the stuff in the home... this involves buying and selling stuff ** not in the 'best' list. * We sell anything we may need later (see step 4) * * (2) Sell items to the shops (for money) * We sell anything we do not actually need * * (3) Buy items from the shops (for the player) * We buy things that we actually need * * (4) Buy items from the home (for the player) * We buy things that we actually need (see step 1) * * (5) Buy items from the shops (for the home) * We buy things we may need later (see step 1) * * (6) Buy items from the home (for the stores) * We buy things we no longer need (see step 2) * * The basic principle is that we should always act to improve our * "status", and we should sometimes act to "maintain" our status, * especially if there is a monetary reward. But first we should * attempt to use the home as a "stockpile", even though that is * not worth any money, since it may save us money eventually. */ #if 0 /* this optimized the home storage by trying every combination... it was too slow.*/ /* put this code back when running this on a Cray. */ static void borg_think_home_sell_aux2( int n, int start_i ) { int i; /* All done */ if (n == STORE_INVEN_MAX) { s32b home_power; /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ home_power = borg_power_home(); /* Track best */ if (home_power > *b_home_power) { /* Save the results */ for (i = 0; i < STORE_INVEN_MAX; i++) best[i] = test[i]; #if 0 /* dump, for debugging */ borg_note(format("Trying Combo (best home power %ld)", *b_home_power)); borg_note(format(" (test home power %ld)",home_power)); for (i = 0; i < STORE_INVEN_MAX; i++) { if (auto_shops[7].ware[i].iqty) borg_note(format("store %d %s (qty-%d).", i, auto_shops[7].ware[i].desc, auto_shops[7].ware[i].iqty )); else borg_note(format("store %d (empty).", i)); } borg_note(" "); /* add a blank line */ #endif /* Use it */ *b_home_power = home_power; } /* Success */ return; } /* Note the attempt */ test[n] = n; /* Evaluate the default item */ borg_think_home_sell_aux2(n + 1, start_i ); /* if this slot and the previous slot is empty, move on to previous slot*/ /* this will prevent trying a thing in all the empty slots to see if */ /* empty slot b is better than empty slot a.*/ if ((n != 0) && !auto_shops[7].ware[n].iqty && !auto_shops[7].ware[n-1].iqty) return; /* try other combinations */ for (i = start_i; i < INVEN_PACK; i++) { auto_item *item; auto_item *item2; bool stacked = FALSE; item = &auto_items[i]; item2= &auto_shops[7].ware[n]; /* Skip empty items */ /* Require "aware" */ /* Require "known" */ if (!item->iqty || !item->kind || !item->able) continue; /* Hack -- ignore "worthless" items */ if (!item->value) continue; /* stacking? */ if (borg_object_similar(item2, item)) { item2->iqty++; item->iqty--; stacked = TRUE; } else { int k; bool found_match = FALSE; /* eliminate items that would stack else where in the list. */ for (k = 0; k < STORE_INVEN_MAX; k++) { if (borg_object_similar(&safe_home[k], item)) { found_match = TRUE; break; } } if (found_match) continue; /* replace current item with this item */ COPY(item2, item, auto_item); /* only move one into a non-stack slot */ item2->iqty = 1; /* remove item from pack */ item->iqty--; } /* Note the attempt */ test[n] = i + STORE_INVEN_MAX; /* Evaluate the possible item */ borg_think_home_sell_aux2( n + 1, i+1 ); /* restore stuff */ COPY(item2, &safe_home[n], auto_item); /* put item back into pack */ item->iqty++; } } #endif /* * this will see what single addition/substitution is best for the home. * The formula is not as nice as the one above because it will * not check all possible combinations of items. but it is MUCH faster. */ static void borg_think_home_sell_aux2( int n, int start_i ) { auto_item *item; auto_item *item2; s32b home_power; int i, k; bool stacked = FALSE; /* get the starting best (current) */ /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ *b_home_power = borg_power_home(); /* try individual substitutions/additions. */ for (n = 0; n < STORE_INVEN_MAX; n++) { item2 = &auto_shops[7].ware[n]; for (i = 0; i < INVEN_PACK; i++) { item = &auto_items[i]; /* Skip empty items */ /* Require "aware" */ /* Require "known" */ if (!item->iqty || !item->kind || !item->able) continue; /* Hack -- ignore "worthless" items */ if (!item->value) continue; /* stacking? */ if (borg_object_similar(item2, item)) { /* if this stacks with what was previously here */ item2->iqty++; stacked = TRUE; } else { bool found_match = FALSE; /* eliminate items that would stack else where in the list. */ for (k = 0; k < STORE_INVEN_MAX; k++) { if (borg_object_similar(&safe_home[k], item)) { found_match = TRUE; break; } } if (found_match) continue; /* replace current item with this item */ COPY(item2, item, auto_item); /* only move one into a non-stack slot */ item2->iqty = 1; } /* remove item from pack */ item->iqty--; /* Note the attempt */ test[n] = i + STORE_INVEN_MAX; /* Test to see if this is a good substitution. */ /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ home_power = borg_power_home(); /* Track best */ if (home_power > *b_home_power) { /* Save the results */ for (k = 0; k < STORE_INVEN_MAX; k++) best[k] = test[k]; #if 0 /* dump, for debugging */ borg_note(format("Trying Combo (best home power %ld)", *b_home_power)); borg_note(format(" (test home power %ld)", home_power)); for (i = 0; i < STORE_INVEN_MAX; i++) if (auto_shops[7].ware[i].iqty) borg_note(format("store %d %s (qty-%d).", i, auto_shops[7].ware[i].desc, auto_shops[7].ware[i].iqty )); else borg_note(format("store %d (empty).", i)); borg_note(" "); /* add a blank line */ #endif /* Use it */ *b_home_power = home_power; } /* restore stuff */ COPY(item2, &safe_home[n], auto_item); /* put item back into pack */ item->iqty++; /* put the item back in the test array */ test[n] = n; } } } static void borg_think_home_sell_aux3( ) { int i; s32b borg_empty_home_power; s32b power; /* get the starting power */ borg_notice(); power = borg_power(); /* get what an empty home would have for power */ borg_notice_home( NULL, TRUE ); borg_empty_home_power = borg_power_home(); /* go through the inventory and eliminate items that either */ /* 1) will not increase the power of an empty house. */ /* 2) will reduce borg_power if given to home */ for (i = 0; i < INVEN_PACK; i++) { int num_items_given; num_items_given = 0; /* if there is no item here, go to next slot */ if (!auto_items[i].iqty) continue; /* 1) eliminate garbage items (items that add nothing to an */ /* empty house) */ borg_notice_home( &auto_items[i], FALSE ); if (borg_power_home() <= borg_empty_home_power) { safe_items[i].iqty = 0; continue; } /* 2) will reduce borg_power if given to home */ while (auto_items[i].iqty) { /* reduce inventory by this item */ num_items_given++; auto_items[i].iqty--; /* Examine borg */ borg_notice(); /* done if this reduces the borgs power */ if (borg_power() < power) { /* we gave up one to many items */ num_items_given--; break; } } /* restore the qty */ auto_items[i].iqty = safe_items[i].iqty; /* set the qty to number given without reducing borg power */ safe_items[i].iqty = num_items_given; } } /* * Step 1 -- sell "useful" things to the home (for later) */ static bool borg_think_home_sell_aux( bool save_best ) { int icky = STORE_INVEN_MAX - 1; s32b home_power = -1L; int i, b_i = -1; byte test_a[STORE_INVEN_MAX]; byte best_a[STORE_INVEN_MAX]; bool fix = FALSE; /* if the best is being saved (see borg_think_shop_grab_aux) */ /* !FIX THIS NEEDS TO BE COMMENTED BETTER */ if (!save_best) b_home_power = &home_power; test = test_a; best = best_a; /* if I have not been to home, do not try this yet. */ if (!auto_shops[7].when) return FALSE; /* Hack -- the home is full */ /* and pack is full */ if (auto_shops[7].ware[icky].iqty && auto_items[INVEN_PACK-1].iqty) return (FALSE); /* Copy all the store slots */ for (i = 0; i < STORE_INVEN_MAX; i++) { /* Save the item */ COPY(&safe_home[i], &auto_shops[7].ware[i], auto_item); /* clear test arrays (test[i] == i is no change) */ best[i] = test[i] = i; } /* Hack -- Copy all the slots */ for (i = 0; i < INVEN_PACK; i++) { /* Save the item */ COPY(&safe_items[i], &auto_items[i], auto_item); } /* get rid of useless items */ borg_think_home_sell_aux3(); /* Examine the borg once more with full inventory then swap in the */ /* safe_items for the home optimization */ borg_notice(); /* swap quantities (this should be all that is different) */ for (i = 0; i < INVEN_PACK; i++) { byte save_qty; save_qty = safe_items[i].iqty; safe_items[i].iqty = auto_items[i].iqty; auto_items[i].iqty = save_qty; } *b_home_power = -1; /* find best combo for home. */ borg_think_home_sell_aux2( 0, 0 ); /* restore bonuses and such */ for (i = 0; i < STORE_INVEN_MAX; i++) { COPY(&auto_shops[7].ware[i], &safe_home[i], auto_item); } for (i = 0; i < INVEN_TOTAL; i++) { COPY(&auto_items[i], &safe_items[i], auto_item); } borg_notice(); borg_notice_home(NULL, FALSE); /* Drop stuff that will stack in the home */ for (i = 0; i < STORE_INVEN_MAX; i++) { /* if this is not the item that was there, */ /* drop off the item that replaces it. */ if (best[i] != i && best[i] != 255) { auto_item *item = &auto_items[best[i]-STORE_INVEN_MAX]; auto_item *item2 = &auto_shops[7].ware[i]; /* if this item is not the same as what was */ /* there before take it. */ if (!borg_object_similar(item2, item)) continue; goal_shop = 7; goal_item = best[i] - STORE_INVEN_MAX; return (TRUE); } } /* Get rid of stuff in house but not in 'best' house if */ /* pack is not full */ if (!auto_items[INVEN_PACK-1].iqty) { for (i = 0; i < STORE_INVEN_MAX; i++) { /* if this is not the item that was there, */ /* get rid of the item that was there */ if ((best[i] != i) && (auto_shops[7].ware[i].iqty)) { auto_item *item = &auto_items[best[i]-STORE_INVEN_MAX]; auto_item *item2 = &auto_shops[7].ware[i]; /* if this item is not the same as what was */ /* there before take it. */ if (borg_object_similar(item, item2)) continue; goal_shop = 7; goal_ware = i; return TRUE; } } } /*/ Drop stuff that is in best house but currently in inventory */ for (i = 0; i < STORE_INVEN_MAX; i++) { /* if this is not the item that was there, */ /* drop off the item that replaces it. */ if (best[i] != i && best[i] != 255) { goal_shop = 7; goal_item = best[i] - STORE_INVEN_MAX; return (TRUE); } } /* Assume not */ return (FALSE); } /* * Determine if an item can be sold in the given store * * XXX XXX XXX Consider use of "icky" test on items */ static bool borg_good_sell(auto_item *item, int who) { /* Never sell worthless items */ if (item->value <= 0) return (FALSE); /* Analyze the type */ switch (item->tval) { case TV_POTION: case TV_SCROLL: /* Never sell if not "known" and interesting */ if (!item->able && (auto_max_depth > 5)) return (FALSE); break; case TV_FOOD: case TV_ROD: case TV_WAND: case TV_STAFF: case TV_RING: case TV_AMULET: case TV_LITE: /* Never sell if not "known" */ if (!item->able) return (FALSE); break; 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: /* Only sell "known" (or "average") items (unless "icky") */ if (!item->able && !streq(item->note, "{average}") && !borg_item_icky(item)) return (FALSE); /* do not sell things that are good/excelent/special until they */ /* have been ID'd */ if (item->able && (streq(item->note, "{good}") || streq(item->note, "{excellent}") || streq(item->note, "{special}"))) return (FALSE); break; } /* Do not sell stuff that is not fully id'd and should be */ if (!item->fully_identified) { switch (item->name2) { /* Weapon (Blessed) */ case EGO_BLESS_BLADE: /* Robe of Permanance */ case EGO_PERMANENCE: /* Armor of Elvenkind */ case EGO_ELVENKIND: /* Crown of the Magi */ case EGO_MAGI: /* Cloak of Aman */ case EGO_AMAN: return (FALSE); /* Weapon (Holy Avenger) */ case EGO_HA: /* Weapon (Defender) */ case EGO_DF: /* anything else */ default: break; } } /* Switch on the store */ switch (who + 1) { /* General Store */ case 1: /* Analyze the type */ switch (item->tval) { case TV_DIGGING: case TV_CLOAK: case TV_FOOD: case TV_FLASK: case TV_LITE: case TV_SPIKE: return (TRUE); } break; /* Armoury */ case 2: /* Analyze the type */ switch (item->tval) { case TV_BOOTS: case TV_GLOVES: #if 0 case TV_CLOAK: #endif case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: case TV_DRAG_ARMOR: return (TRUE); } break; /* Weapon Shop */ case 3: /* Analyze the type */ switch (item->tval) { case TV_SHOT: case TV_BOLT: case TV_ARROW: case TV_BOW: #if 0 case TV_DIGGING: case TV_HAFTED: #endif case TV_POLEARM: case TV_SWORD: return (TRUE); } break; /* Temple */ case 4: /* Analyze the type */ switch (item->tval) { case TV_HAFTED: #if 0 case TV_SCROLL: case TV_POTION: #endif case TV_PRAYER_BOOK: return (TRUE); } break; /* Alchemist */ case 5: /* Analyze the type */ switch (item->tval) { case TV_SCROLL: case TV_POTION: return (TRUE); } break; /* Magic Shop */ case 6: /* Analyze the type */ switch (item->tval) { case TV_MAGIC_BOOK: case TV_AMULET: case TV_RING: #if 0 case TV_SCROLL: case TV_POTION: #endif case TV_STAFF: case TV_WAND: case TV_ROD: return (TRUE); } break; /* Black Market */ case 7: /* Analyze the type */ switch (item->tval) { case TV_CHEST: return (TRUE); } break; } /* Assume not */ return (FALSE); } /* * Step 2 -- sell "useless" items to a shop (for cash) */ static bool borg_think_shop_sell_aux(void) { int icky = STORE_INVEN_MAX - 1; int k, b_k = -1; int i, b_i = -1; s32b p, b_p = 0L; s32b c = 0L; s32b b_c = 30001L; bool fix = FALSE; /* Evaluate */ b_p = my_power; /* Check each shop */ for (k = 0; k < 7; k++) { /* Hack -- Skip "full" shops */ if (auto_shops[k].ware[icky].iqty) continue; /* Save the store hole */ COPY(&safe_shops[k].ware[icky], &auto_shops[k].ware[icky], auto_item); /* Sell stuff */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip "bad" sales */ if (!borg_good_sell(item, k)) continue; /* Save the item */ COPY(&safe_items[i], &auto_items[i], auto_item); /* Give the item to the shop */ COPY(&auto_shops[k].ware[icky], &safe_items[i], auto_item); /* Give a single item */ auto_shops[k].ware[icky].iqty = 1; /* Lose a single item */ 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); /* Ignore "bad" sales */ if (p < b_p) continue; /* Extract the "price" */ c = ((item->value < 30000L) ? item->value : 30000L); /* sell cheap items first. This is done because we may have to */ /* buy the item back in some very strange cercemstances. */ if ((p == b_p) && (c >= b_c)) continue; /* Maintain the "best" */ b_k = k; b_i = i; b_p = p; b_c = c; } /* Restore the store hole */ COPY(&auto_shops[k].ware[icky], &safe_shops[k].ware[icky], auto_item); } /* Examine the inventory */ if (fix) borg_notice(); /* Sell something (if useless) */ if ((b_k >= 0) && (b_i >= 0)) { /* Visit that shop */ goal_shop = b_k; /* Sell that item */ goal_item = b_i; /* Success */ return (TRUE); } /* Assume not */ return (FALSE); } /* * Help decide if an item should be bought from a real store * * We prevent the purchase of enchanted (or expensive) ammo, * so we do not spend all our money on temporary power. * if below level 35, who needs cash? buy the expecive ammo! * * We prevent the purchase of low level discounted books, * so we will not waste slots on cheap books. * * We prevent the purchase of items from the black market * which are often available at normal stores, currently, * this includes low level books, and all wands and staffs. */ static bool borg_good_buy(auto_item *item, int who) { /* Check the object */ switch (item->tval) { case TV_DIGGING: return (FALSE); case TV_SHOT: case TV_ARROW: case TV_BOLT: if (auto_depth < 35) { if (item->to_h) return (FALSE); if (item->to_d) return (FALSE); } if (who == 6) return (FALSE); break; case TV_MAGIC_BOOK: case TV_PRAYER_BOOK: if (item->sval >= 4) break; if (item->discount) return (FALSE); if (who == 6) return (FALSE); break; case TV_WAND: case TV_STAFF: if (who == 6) return (FALSE); break; } /* Okay */ return (TRUE); } /* * Step 3 -- buy "useful" things from a shop (to be used) */ static bool borg_think_shop_buy_aux(void) { int hole = INVEN_PACK - 1; int slot; int k, b_k = -1; int n, b_n = -1; s32b p, b_p = 0L; s32b c, b_c = 0L; bool fix = FALSE; /* Require one empty slot */ if (auto_items[hole].iqty) return (FALSE); /* Extract the "power" */ b_p = my_power; /* Check the shops */ for (k = 0; k < 7; k++) { /* Scan the wares */ for (n = 0; n < STORE_INVEN_MAX; n++) { auto_item *item = &auto_shops[k].ware[n]; /* Skip empty items */ if (!item->iqty) continue; /* Skip "bad" buys */ if (!borg_good_buy(item, k)) continue; /* Hack -- Require "sufficient" cash */ if (auto_gold < item->cost * 12 / 10) continue; /* Save shop item */ COPY(&safe_shops[k].ware[n], &auto_shops[k].ware[n], auto_item); /* Save hole */ COPY(&safe_items[hole], &auto_items[hole], auto_item); /* Remove one item from shop */ auto_shops[k].ware[n].iqty--; /* Obtain "slot" */ slot = borg_wield_slot(item); /* Consider new equipment */ if (slot >= 0) { /* Save old item */ COPY(&safe_items[slot], &auto_items[slot], auto_item); /* Move equipment into inventory */ COPY(&auto_items[hole], &safe_items[slot], auto_item); /* Move new item into equipment */ COPY(&auto_items[slot], &safe_shops[k].ware[n], auto_item); /* Only a single item */ auto_items[slot].iqty = 1; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ p = borg_power(); /* Restore old item */ COPY(&auto_items[slot], &safe_items[slot], auto_item); } /* Consider new inventory */ else { /* Move new item into inventory */ COPY(&auto_items[hole], &safe_shops[k].ware[n], auto_item); /* Only a single item */ auto_items[hole].iqty = 1; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the equipment */ p = borg_power(); } /* Restore hole */ COPY(&auto_items[hole], &safe_items[hole], auto_item); /* Restore shop item */ COPY(&auto_shops[k].ware[n], &safe_shops[k].ware[n], auto_item); /* Obtain the "cost" of the item */ c = item->cost; /* Penalize the cost of expensive items */ if (c > auto_gold / 10) p -= c; /* Ignore "bad" purchases */ if (p < b_p) continue; /* Ignore "expensive" purchases */ if ((p == b_p) && (c >= b_c)) continue; /* Save the item and cost */ b_k = k; b_n = n; b_p = p; b_c = c; } } /* Examine the inventory */ if (fix) borg_notice(); /* Buy something */ if ((b_k >= 0) && (b_n >= 0)) { /* Visit that shop */ goal_shop = b_k; /* Buy that item */ goal_ware = b_n; /* Success */ return (TRUE); } /* Nope */ return (FALSE); } /* * Step 4 -- buy "useful" things from the home (to be used) */ static bool borg_think_home_buy_aux(void) { int hole = INVEN_PACK - 1; int slot; int n, b_n = -1; s32b p, b_p = 0L; bool fix = FALSE; /* Require one empty slot */ if (auto_items[hole].iqty) return (FALSE); /* Extract the "power" */ b_p = my_power; /* Scan the home */ for (n = 0; n < STORE_INVEN_MAX; n++) { auto_item *item = &auto_shops[7].ware[n]; /* Skip empty items */ if (!item->iqty) continue; /* Save shop item */ COPY(&safe_shops[7].ware[n], &auto_shops[7].ware[n], auto_item); /* Save hole */ COPY(&safe_items[hole], &auto_items[hole], auto_item); /* Remove one item from shop */ auto_shops[7].ware[n].iqty--; /* Obtain "slot" */ slot = borg_wield_slot(item); /* Consider new equipment */ if (slot >= 0) { /* Save old item */ COPY(&safe_items[slot], &auto_items[slot], auto_item); /* Move equipment into inventory */ COPY(&auto_items[hole], &safe_items[slot], auto_item); /* Move new item into equipment */ COPY(&auto_items[slot], &safe_shops[7].ware[n], auto_item); /* Only a single item */ auto_items[slot].iqty = 1; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the inventory */ p = borg_power(); /* Restore old item */ COPY(&auto_items[slot], &safe_items[slot], auto_item); } /* Consider new inventory */ else { /* Move new item into inventory */ COPY(&auto_items[hole], &safe_shops[7].ware[n], auto_item); /* Only a single item */ auto_items[hole].iqty = 1; /* Fix later */ fix = TRUE; /* Examine the inventory */ borg_notice(); /* Evaluate the equipment */ p = borg_power(); } /* Restore hole */ COPY(&auto_items[hole], &safe_items[hole], auto_item); /* Restore shop item */ COPY(&auto_shops[7].ware[n], &safe_shops[7].ware[n], auto_item); /* Ignore "silly" purchases */ if (p <= b_p) continue; /* Save the item and cost */ b_n = n; b_p = p; } /* Examine the inventory */ if (fix) borg_notice(); /* Buy something */ if ((b_n >= 0) && (b_p > my_power)) { /* Go to the home */ goal_shop = 7; /* Buy that item */ goal_ware = b_n; /* Success */ return (TRUE); } /* Nope */ return (FALSE); } /* * Step 5 -- buy "interesting" things from a shop (to be used later) */ static bool borg_think_shop_grab_aux(void) { int icky = STORE_INVEN_MAX - 1; int k, b_k = -1; int n, b_n = -1; s32b s, b_s = 0L; s32b c, b_c = 0L; s32b borg_empty_home_power; /* get what an empty home would have for power */ borg_notice_home( NULL, TRUE ); borg_empty_home_power = borg_power_home(); b_home_power = &s; /* Require two empty slots */ if (auto_items[INVEN_PACK-1].iqty) return (FALSE); if (auto_items[INVEN_PACK-2].iqty) return (FALSE); /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ b_s = borg_power_home(); /* Check the shops */ for (k = 0; k < 7; k++) { /* Scan the wares */ for (n = 0; n < STORE_INVEN_MAX; n++) { auto_item *item = &auto_shops[k].ware[n]; /* Skip empty items */ if (!item->iqty) continue; /* Skip "bad" buys */ if (!borg_good_buy(item, k)) continue; /* Hack -- Require some "extra" cash */ if (auto_gold < 1000L + item->cost * 5) continue; /* make this the next to last item that the player has */ /* (can't make it the last or it thinks that both player and */ /* home are full) */ COPY(&auto_items[INVEN_PACK-2], &auto_shops[k].ware[n], auto_item); /* Give a single item */ auto_items[INVEN_PACK-2].iqty = 1; /* make sure this item would help an empty home */ borg_notice_home( &auto_shops[k].ware[n], FALSE ); if (borg_empty_home_power >= borg_power_home()) continue; /* optimize the home inventory */ if (!borg_think_home_sell_aux( TRUE )) continue; /* Obtain the "cost" of the item */ c = item->cost; /* Penalize expensive items */ if (c > auto_gold / 10) s -= c; /* Ignore "bad" sales */ if (s < b_s) continue; /* Ignore "expensive" purchases */ if ((s == b_s) && (c >= b_c)) continue; /* Save the item and cost */ b_k = k; b_n = n; b_s = s; b_c = c; } } /* restore inventory hole (just make sure the last slot goes back to */ /* empty) */ auto_items[INVEN_PACK-2].iqty = 0; /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ s = borg_power_home(); /* remove the target that optimizing the home gave */ goal_shop = goal_ware = goal_item = -1; /* Buy something */ if ((b_k >= 0) && (b_n >= 0)) { /* Visit that shop */ goal_shop = b_k; /* Buy that item */ goal_ware = b_n; /* Success */ return (TRUE); } /* Nope */ return (FALSE); } /* * Step 6 -- take "useless" things from the home (to be sold) */ static bool borg_think_home_grab_aux(void) { int n, b_n = -1; s32b s, b_s = 0L; /* Require two empty slots */ if (auto_items[INVEN_PACK-1].iqty) return (FALSE); if (auto_items[INVEN_PACK-2].iqty) return (FALSE); /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ b_s = borg_power_home(); /* Scan the home */ for (n = 0; n < STORE_INVEN_MAX; n++) { auto_item *item = &auto_shops[7].ware[n]; /* Skip empty items */ if (!item->iqty) continue; /* Save shop item */ COPY(&safe_shops[7].ware[n], &auto_shops[7].ware[n], auto_item); /* Remove one item from shop */ auto_shops[7].ware[n].iqty--; /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ s = borg_power_home(); /* Restore shop item */ COPY(&auto_shops[7].ware[n], &safe_shops[7].ware[n], auto_item); /* Ignore "bad" sales */ if (s < b_s) continue; /* Maintain the "best" */ b_n = n; b_s = s; } /* Examine the home */ borg_notice_home(NULL, FALSE); /* Evaluate the home */ s = borg_power_home(); /* Stockpile */ if (b_n >= 0) { /* Visit the home */ goal_shop = 7; /* Grab that item */ goal_ware = b_n; /* Success */ return (TRUE); } /* Assume not */ return (FALSE); } /* * Choose a shop to visit (see above) */ static bool borg_choose_shop(void) { int i; /* Must be in town */ if (auto_depth) return (FALSE); /* Must have complete information */ for (i = 0; i < 8; i++) { auto_shop *shop = &auto_shops[i]; /* Skip "visited" shops */ if (!shop->when) return (FALSE); } /* if we are already flowing toward a shop do not check again... */ if (goal_shop != -1) return TRUE; /* Assume no important shop */ goal_shop = goal_ware = goal_item = -1; /* Step 1 -- Sell items to the home */ if (borg_think_home_sell_aux( FALSE )) { /* Message */ if (goal_item != -1) borg_note(format("# Selling '%s' to the home", auto_items[goal_item].desc)); else borg_note(format("# Buying '%s' from the home", auto_shops[goal_shop].ware[goal_ware].desc)); /* Success */ return (TRUE); } /* Step 2 -- Sell items to the shops */ if (borg_think_shop_sell_aux()) { /* Message */ borg_note(format("# Selling '%s' at '%s'", auto_items[goal_item].desc, (f_name + f_info[0x08+goal_shop].name))); /* Success */ return (TRUE); } /* Step 3 -- Buy items from the shops (for the player) */ if (borg_think_shop_buy_aux()) { /* Message */ borg_note(format("# Buying '%s' at '%s' (for player)", auto_shops[goal_shop].ware[goal_ware].desc, (f_name + f_info[0x08+goal_shop].name))); /* Success */ return (TRUE); } /* Step 4 -- Buy items from the home (for the player) */ if (borg_think_home_buy_aux()) { /* Message */ borg_note(format("# Buying '%s' from the home", auto_shops[goal_shop].ware[goal_ware].desc)); /* Success */ return (TRUE); } /* get rid of junk from home first. That way the home is 'uncluttered' */ /* before you buy stuff for it. This will prevent the problem where an */ /* item has become a negative value and swapping in a '0' gain item */ /* (like pottery) is better. */ /* Step 5 -- Grab items from the home (for the shops) */ if (borg_think_home_grab_aux()) { /* Message */ borg_note(format("# Grabbing (to sell) '%s' from the home", auto_shops[goal_shop].ware[goal_ware].desc)); /* Success */ return (TRUE); } /* Step 6 -- Buy items from the shops (for the home) */ if (borg_think_shop_grab_aux()) { /* Message */ borg_note(format("# Grabbing (for home) '%s' at '%s'", auto_shops[goal_shop].ware[goal_ware].desc, (f_name + f_info[0x08+goal_shop].name))); /* Success */ return (TRUE); } /* Failure */ return (FALSE); } /* * Sell items to the current shop, if desired */ static bool borg_think_shop_sell(void) { /* Sell something if requested */ if ((goal_shop == shop_num) && (goal_item >= 0)) { auto_shop *shop = &auto_shops[goal_shop]; auto_item *item = &auto_items[goal_item]; /* Log */ borg_note(format("# Selling %s", item->desc)); /* Buy an item */ borg_keypress('s'); /* Buy the desired item */ borg_keypress(I2A(goal_item)); /* Hack -- Sell a single item */ if (item->iqty > 1) borg_keypress('\n'); /* Mega-Hack -- Accept the price */ borg_keypress('\n'); borg_keypress('\n'); borg_keypress('\n'); borg_keypress('\n'); /* The purchase is complete */ goal_shop = goal_item = -1; /* Success */ return (TRUE); } /* Nope */ return (FALSE); } /* * Buy items from the current shop, if desired */ static bool borg_think_shop_buy(void) { /* Buy something if requested */ if ((goal_shop == shop_num) && (goal_ware >= 0)) { auto_shop *shop = &auto_shops[goal_shop]; auto_item *item = &shop->ware[goal_ware]; /* Minor Hack -- Go to the correct page */ if ((goal_ware / 12) != shop->page) borg_keypress(' '); /* Log */ borg_note(format("# Buying %s.", item->desc)); /* Buy an item */ borg_keypress('p'); /* Buy the desired item */ borg_keypress(I2A(goal_ware % 12)); /* Hack -- Buy a single item */ if (item->iqty > 1) borg_keypress('\n'); /* Mega-Hack -- Accept the price */ borg_keypress('\n'); borg_keypress('\n'); borg_keypress('\n'); borg_keypress('\n'); /* The purchase is complete */ goal_shop = goal_ware = -1; /* Success */ return (TRUE); } /* Nothing to buy */ return (FALSE); } /* * Deal with being in a store */ bool borg_think_store(void) { /* Stamp the shop with a time stamp */ auto_shops[shop_num].when = c_t; /* Remove "backwards" rings */ if (borg_swap_rings()) return (TRUE); /* Repair "backwards" rings */ if (borg_wear_rings()) return (TRUE); /* Wear "optimal" equipment */ if (borg_best_stuff()) return (TRUE); /* Wear "useful" equipment */ /* if (borg_wear_stuff()) return (TRUE); */ /* Remove "useless" equipment */ if (borg_takeoff_stuff()) return (TRUE); /* Choose a shop to visit */ if (borg_choose_shop()) { /* Try to sell stuff */ if (borg_think_shop_sell()) return (TRUE); /* Try to buy stuff */ if (borg_think_shop_buy()) return (TRUE); } /* No shop */ shop_num = -1; /* Leave the store */ borg_keypress(ESCAPE); /* Done */ return (TRUE); } /* * Hack -- perform an action in the dungeon under boosted bravery * * This function is a sub-set of the standard dungeon goals, and is * only executed when all of the standard dungeon goals fail, because * of excessive danger, or because the level is "bizarre". */ static bool borg_think_dungeon_brave(void) { /*** Local stuff ***/ /* Attack monsters */ if (borg_attack()) return (TRUE); /* Continue flowing towards monsters */ if (borg_flow_old(GOAL_KILL)) return (TRUE); /* Find a (viewable) monster */ if (borg_flow_kill(TRUE)) return (TRUE); /* Continue flowing towards objects */ if (borg_flow_old(GOAL_TAKE)) return (TRUE); /* Find a (viewable) object */ if (borg_flow_take(TRUE)) return (TRUE); /*** Flee (or leave) the level ***/ /* Flee the level */ if (goal_fleeing || goal_leaving) { /* Hack -- Take the next stairs */ stair_less = goal_fleeing; if (borg_ready_morgoth == 0) stair_less = TRUE; /* Only go down if fleeing or prepared. */ stair_more = goal_fleeing; if ((cptr)NULL == borg_prepared(auto_depth+1)) stair_more = TRUE; /* Continue fleeing the level */ if (borg_flow_old(GOAL_FLEE)) return (TRUE); /* Try to find some stairs up */ if (borg_flow_stair_less(GOAL_FLEE)) return (TRUE); /* Try to find some stairs down */ if (borg_flow_stair_more(GOAL_FLEE)) return (TRUE); } /*** Exploration ***/ /* Continue flowing (see below) */ if (borg_flow_old(GOAL_MISC)) return (TRUE); /* Continue flowing (see below) */ if (borg_flow_old(GOAL_DARK)) return (TRUE); /* Continue flowing (see below) */ if (borg_flow_old(GOAL_XTRA)) return (TRUE); /* Continue flowing (see below) */ if (borg_flow_old(GOAL_BORE)) return (TRUE); /*** Explore the dungeon ***/ /* Explore interesting grids */ if (borg_flow_dark(TRUE)) return (TRUE); /* Explore interesting grids */ if (borg_flow_dark(FALSE)) return (TRUE); /* Search for secret doors */ if (borg_flow_spastic(FALSE)) return (TRUE); /*** Track down old stuff ***/ /* Chase old objects */ if (borg_flow_take(FALSE)) return (TRUE); /* Chase old monsters */ if (borg_flow_kill(FALSE)) return (TRUE); /* Search for secret doors */ if (borg_flow_spastic(TRUE)) return (TRUE); /* Nothing */ return (FALSE); } /* * Check a 'hidden' stat * * if we need to check our stats still that is because the stat * was above 18/220 so we need to take off some stuff to check * what our *real* base stat is. * * If we do not have a free slot, this is dangerious because we may * drop our stuff. It is better to drop the stuff than to take * the chance that we would take off our ring of int +6 then crush it * because we are full. */ static bool borg_check_stats() { int i, x; int sv_p = -1, b_x = -1; /* check to make sure one stat needs checking */ if (!my_need_stat_check[0] && !my_need_stat_check[1] && !my_need_stat_check[2] && !my_need_stat_check[3] && !my_need_stat_check[4] && !my_need_stat_check[5]) return (FALSE); /* if in any danger, do this later. The guess that we */ /* did for our stat will do for now.*/ if (borg_danger(c_y, c_x, 3) > 0) return (FALSE); /* Check the equiptment for anything that is not ID'd yet. */ /* do not check stats until everything you have on is ID'd */ 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 or */ /* stats. */ if (!item->able) return (FALSE); } /* look for a stat that needs to be checked */ for (i = 0; i < 6; i++) { if (!my_need_stat_check[i]) continue; /* look for an item that is giving that stat a bonus */ for (x = INVEN_WIELD; x < INVEN_TOTAL; x ++) { auto_item *item = &auto_items[x]; /* Skip empty slots */ if (!item->iqty) continue; /* If this item does not give a bonus to the stat we */ /* are checking get the next item. */ if (!(item->flags1 & TR1_STR) && i == 0) continue; if (!(item->flags1 & TR1_INT) && i == 1) continue; if (!(item->flags1 & TR1_WIS) && i == 2) continue; if (!(item->flags1 & TR1_DEX) && i == 3) continue; if (!(item->flags1 & TR1_CON) && i == 4) continue; if (!(item->flags1 & TR1_CHR) && i == 5) continue; /* save the item with the highest bonus */ if (item->pval > sv_p) { sv_p = item->pval; b_x = x; } } /* Make sure we found an item */ if (b_x == -1) return (FALSE); /* Log */ borg_note(format("# Taking off %s. (to check stats)", auto_items[b_x].desc)); /* Take the item off. When it is off our stat will be less than */ /* 18/220 (hopefully) and borg_hidden will guess the right value. */ borg_keypress('t'); borg_keypress(I2A(b_x - INVEN_WIELD)); return (TRUE); } return (FALSE); } /* * Perform an action in the dungeon * * Return TRUE if a "meaningful" action was performed * Otherwise, return FALSE so we will be called again * * Strategy: * Make sure we are happy with our "status" (see above) * Attack and kill visible monsters, if near enough * Open doors, disarm traps, tunnel through rubble * Pick up (or tunnel to) gold and useful objects * Explore "interesting" grids, to expand the map * Explore the dungeon and revisit old grids * * Fleeing: * Use word of recall when level is "scary" * Flee to stairs when there is a chance of death * Avoid "stair bouncing" if at all possible * * Note that the various "flow" actions allow the Borg to flow * "through" closed doors, which will be opened when he attempts * to pass through them, so we do not have to pursue terrain until * all monsters and objects have been dealt with. * * XXX XXX XXX The poor Borg often kills a nasty monster, and * then takes a nap to recover from damage, but gets yanked * back to town before he can collect his reward. */ bool borg_think_dungeon(void) { int i, j; /* Hack -- prevent clock wrapping */ if (c_t >= 30000) { /* Panic */ borg_oops("clock overflow"); /* Oops */ return (TRUE); } /* Prevent clock overflow */ if (c_t - auto_began >= 10000) { /* Start leaving */ if (!goal_leaving) { /* Note */ borg_note("# Leaving (boredom)"); /* Start leaving */ goal_leaving = TRUE; } /* Start fleeing */ if (!goal_fleeing) { /* Note */ borg_note("# Fleeing (boredom)"); /* Start fleeing */ goal_fleeing = TRUE; } } /* Avoid annoying farming */ if (c_t - auto_began >= 2000) { /* Ignore monsters from boredom */ if (!goal_ignoring) { /* Flee */ borg_note("# Ignoring breeders (boredom)"); /* Ignore multipliers */ goal_ignoring = TRUE; } } /* Count the awake breeders */ for (j = 0, i = 1; i < auto_kills_nxt; i++) { auto_kill *kill = &auto_kills[i]; /* Skip dead monsters */ if (!kill->r_idx) continue; /* Skip sleeping monsters */ if (!kill->awake) continue; /* Count the monsters which are "breeders" */ if (r_info[kill->r_idx].flags2 & RF2_MULTIPLY) j++; } /* Hack -- caution */ if (j && (amt_recall <= 0)) { /* Ignore monsters from caution */ if (!goal_ignoring) { /* Flee */ borg_note("# Ignoring breeders (no recall)"); /* Ignore multipliers */ goal_ignoring = TRUE; } /* Start leaving */ if (!goal_leaving) { /* Note */ borg_note("# Leaving (no recall)"); /* Start leaving */ goal_leaving = TRUE; } /* Start fleeing */ if (!goal_fleeing) { /* Note */ borg_note("# Fleeing (no recall)"); /* Start fleeing */ goal_fleeing = TRUE; } } /* Reset avoidance */ if (avoidance != auto_chp) { /* Reset "avoidance" */ avoidance = auto_chp; /* Re-calculate danger */ auto_danger_wipe = TRUE; /* Forget goals */ goal = 0; } /*** Important goals ***/ /* Try not to die */ if (borg_caution()) return (TRUE); /* I may need to strip off some stuff to check my stats. */ if (borg_check_stats()) return (TRUE); /* Wear things that need to be worn */ if (borg_wear_stuff()) return (TRUE); /* Learn useful spells immediately */ if (borg_play_magic(FALSE)) return (TRUE); /* Attack monsters */ if (borg_attack()) return (TRUE); /* Recover from damage */ if (borg_recover()) return (TRUE); /* Continue flowing towards monsters */ if (borg_flow_old(GOAL_KILL)) return (TRUE); /* Find a (viewable) monster */ if (borg_flow_kill(TRUE)) return (TRUE); /*** Deal with inventory objects ***/ /* Check the light */ if (borg_check_lite()) return (TRUE); /* Use things */ if (borg_use_things()) return (TRUE); /* Identify unknown things */ if (borg_test_stuff(FALSE)) return (TRUE); /* *Id* unknown things */ if (borg_test_stuff(TRUE)) return (TRUE); /* Enchant things */ if (borg_enchanting()) return (TRUE); /* Recharge things */ if (borg_recharging()) return (TRUE); /* Destroy junk */ if (borg_crush_junk()) return (TRUE); /* Destroy items to make space */ if (borg_crush_hole()) return (TRUE); /* Destroy items if we are slow */ if (borg_crush_slow()) return (TRUE); /*** Flee the level XXX XXX XXX ***/ /* Flee the level */ if (goal_fleeing && !goal_recalling) { /* Hack -- Take the next stairs */ stair_less = stair_more = TRUE; /* Continue fleeing the level */ if (borg_flow_old(GOAL_FLEE)) return (TRUE); /* Try to find some stairs up */ if (borg_flow_stair_less(GOAL_FLEE)) return (TRUE); /* Try to find some stairs down */ if (borg_flow_stair_more(GOAL_FLEE)) return (TRUE); } /*** Flow towards objects ***/ /* Continue flowing towards objects */ if (borg_flow_old(GOAL_TAKE)) return (TRUE); /* Find a (viewable) object */ if (borg_flow_take(TRUE)) return (TRUE); /*** Leave the level XXX XXX XXX ***/ /* Leave the level */ if (goal_leaving && !goal_recalling) { /* Hack -- Take the next stairs */ if (borg_ready_morgoth == 0) stair_less = TRUE; /* Only go down if fleeing or prepared. */ if ((cptr)NULL == borg_prepared(auto_depth+1)) stair_more = TRUE; /* Continue leaving the level */ if (borg_flow_old(GOAL_FLEE)) return (TRUE); /* Try to find some stairs up */ if (borg_flow_stair_less(GOAL_FLEE)) return (TRUE); /* Try to find some stairs down */ if (borg_flow_stair_more(GOAL_FLEE)) return (TRUE); } /*** Exploration ***/ /* Continue flowing (see below) */ if (borg_flow_old(GOAL_MISC)) return (TRUE); /* Continue flowing (see below) */ if (borg_flow_old(GOAL_DARK)) return (TRUE); /* Continue flowing (see below) */ if (borg_flow_old(GOAL_XTRA)) return (TRUE); /* Continue flowing (see below) */ if (borg_flow_old(GOAL_BORE)) return (TRUE); /*** Explore the dungeon ***/ /* Chase old monsters */ if (borg_flow_kill(FALSE)) return (TRUE); /* Chase old objects */ if (borg_flow_take(FALSE)) return (TRUE); /* Explore interesting grids */ if (borg_flow_dark(TRUE)) return (TRUE); /* Leave the level (if needed) */ if (borg_leave_level(FALSE)) return (TRUE); /* Explore interesting grids */ if (borg_flow_dark(FALSE)) return (TRUE); /*** Deal with shops ***/ /* Hack -- visit all the shops */ if (borg_flow_shop_visit()) return (TRUE); /* Hack -- Visit the shops */ if (borg_choose_shop()) { /* Try and visit a shop, if so desired */ if (borg_flow_shop_entry(goal_shop)) return (TRUE); } /*** Leave the Level ***/ /* Study/Test boring spells/prayers */ if (borg_play_magic(TRUE)) return (TRUE); /* Search for secret doors */ if (borg_flow_spastic(FALSE)) return (TRUE); /* Leave the level (if possible) */ if (borg_leave_level(TRUE)) return (TRUE); /* Search for secret doors */ if (borg_flow_spastic(TRUE)) return (TRUE); /*** Wait for recall ***/ /* Wait for recall, unless in danger */ if (goal_recalling && (borg_danger(c_y, c_x, 1) <= 0)) { /* Take note */ borg_note("# Waiting for Recall..."); /* Rest until done */ borg_keypress('R'); borg_keypress('&'); borg_keypress('\n'); /* Done */ return (TRUE); } /*** Nothing to do ***/ borg_times_twitch++; /* Teleport to get out of being twitchy up to 5 times per level. */ if (borg_times_twitch < 5) { borg_note("# Teleport (twitchy)"); /* Teleport */ if ( borg_spell(1, 5) || borg_prayer(4, 1) || borg_prayer(1, 1) || borg_use_staff(SV_STAFF_TELEPORTATION)) { /* Success */ return (TRUE); } } /* Start leaving */ if (!goal_leaving) { /* Note */ borg_note("# Leaving (twitchy)"); /* Start leaving */ goal_leaving = TRUE; } /* Start fleeing */ if (!goal_fleeing) { /* Note */ borg_note("# Fleeing (twitchy)"); /* Start fleeing */ goal_fleeing = TRUE; } /* Recall to town */ if (auto_depth && (borg_recall())) { /* Note */ borg_note("# Recalling (twitchy)"); /* Success */ return (TRUE); } /* Boost slightly */ if (avoidance < auto_chp * 2) { bool done = FALSE; /* Note */ borg_note(format("# Boosting bravery (1) from %d to %d!", avoidance, auto_chp * 2)); /* Hack -- ignore some danger */ avoidance = (auto_chp * 2); /* Forget the danger fields */ auto_danger_wipe = TRUE; /* Try anything */ if (borg_think_dungeon_brave()) done = TRUE; /* Reset "avoidance" */ avoidance = auto_chp; /* Re-calculate danger */ auto_danger_wipe = TRUE; /* Forget goals */ goal = 0; /* Done */ if (done) return (TRUE); } /* Boost some more */ if (avoidance < auto_mhp * 4) { bool done = FALSE; /* Note */ borg_note(format("# Boosting bravery (2) from %d to %d!", avoidance, auto_mhp * 4)); /* Hack -- ignore some danger */ avoidance = (auto_mhp * 4); /* Forget the danger fields */ auto_danger_wipe = TRUE; /* Try anything */ if (borg_think_dungeon_brave()) done = TRUE; /* Reset "avoidance" */ avoidance = auto_chp; /* Re-calculate danger */ auto_danger_wipe = TRUE; /* Forget goals */ goal = 0; /* Done */ if (done) return (TRUE); } /* Boost a lot */ if (avoidance < 30000) { bool done = FALSE; /* Note */ borg_note(format("# Boosting bravery (3) from %d to %d!", avoidance, 30000)); /* Hack -- ignore some danger */ avoidance = 30000; /* Forget the danger fields */ auto_danger_wipe = TRUE; /* Try anything */ if (borg_think_dungeon_brave()) done = TRUE; /* Reset "avoidance" */ avoidance = auto_chp; /* Re-calculate danger */ auto_danger_wipe = TRUE; /* Forget goals */ goal = 0; /* Done */ if (done) return (TRUE); } /* Twitch around */ if (borg_twitchy()) return (TRUE); /* Oops */ return (FALSE); } /* * Initialize this file */ void borg_init_8(void) { /* Nothing */ } #else #ifdef MACINTOSH static int HACK = 0; #endif #endif