/* * Know inventory and home items upon death */ static void death_knowledge(void) { store_type *st_ptr = &store[STORE_HOME]; object_type *o_ptr; int i; for (i = 0; i < ALL_INVEN_TOTAL; i++) { o_ptr = &p_ptr->inventory[i]; if (!o_ptr->kind) continue; object_flavor_aware(o_ptr); object_notice_everything(o_ptr); } for (i = 0; i < st_ptr->stock_num; i++) { o_ptr = &st_ptr->stock[i]; if (!o_ptr->kind) continue; object_flavor_aware(o_ptr); object_notice_everything(o_ptr); } history_unmask_unknown(); /* Hack -- Recalculate bonuses */ p_ptr->update |= (PU_BONUS); handle_stuff(p_ptr); }
/* * Become aware of a lot of objects */ static void do_cmd_wiz_learn(void) { int i; object_type *i_ptr; object_type object_type_body; /* Scan every object */ for (i = 1; i < z_info->k_max; i++) { object_kind *k_ptr = &k_info[i]; if (!k_ptr || !k_ptr->name) continue; /* Induce awareness */ if (k_ptr->level <= p_ptr->command_arg) { /* Get local object */ i_ptr = &object_type_body; /* Prepare object */ object_prep(i_ptr, k_ptr, 0, MAXIMISE); /* Awareness */ object_flavor_aware(i_ptr); } } msg("You now know about many items!"); }
/** * Notice the "effect" from activating an object. * * \param o_ptr is the object to become aware of */ void object_notice_effect(object_type *o_ptr) { if (object_add_ident_flags(o_ptr, IDENT_EFFECT)) object_check_for_ident(o_ptr); /* noticing an effect gains awareness */ if (!object_flavor_is_aware(o_ptr)) object_flavor_aware(o_ptr); }
/** * Notice things about an object that would be noticed in time. */ static void object_notice_after_time(void) { int i; int flag; object_type *o_ptr; char o_name[80]; bitflag f[OF_SIZE], timed_mask[OF_SIZE]; flags_init(timed_mask, OF_SIZE, OF_NOTICE_TIMED_MASK, FLAG_END); /* Check every item the player is wearing */ for (i = INVEN_WIELD; i < ALL_INVEN_TOTAL; i++) { o_ptr = &p_ptr->inventory[i]; if (!o_ptr->k_idx || object_is_known(o_ptr)) continue; /* Check for timed notice flags */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); object_flags(o_ptr, f); of_inter(f, timed_mask); for (flag = of_next(f, FLAG_START); flag != FLAG_END; flag = of_next(f, flag + 1)) { if (!of_has(o_ptr->known_flags, flag)) { /* Message */ if (!streq(msgs[flag], "")) msg_format(msgs[flag], o_name); /* Notice the flag */ object_notice_flag(o_ptr, flag); if (object_is_jewelry(o_ptr) && (!object_effect(o_ptr) || object_effect_is_known(o_ptr))) { /* XXX this is a small hack, but jewelry with anything noticeable really is obvious */ /* XXX except, wait until learn activation if that is only clue */ object_flavor_aware(o_ptr); object_check_for_ident(o_ptr); } } else { /* Notice the flag is absent */ object_notice_flag(o_ptr, flag); } } /* XXX Is this necessary? */ object_check_for_ident(o_ptr); } }
/** * Notice a given special flag on wielded items. * * \param flag is the flag to notice */ void wieldeds_notice_flag(int flag) { int i; /* XXX Eddie need different naming conventions for starting wieldeds at INVEN_WIELD vs INVEN_WIELD+2 */ for (i = INVEN_WIELD; i < ALL_INVEN_TOTAL; i++) { object_type *o_ptr = &p_ptr->inventory[i]; bitflag f[OF_SIZE]; if (!o_ptr->k_idx) continue; object_flags(o_ptr, f); if (of_has(f, flag) && !of_has(o_ptr->known_flags, flag)) { char o_name[80]; object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); /* Notice the flag */ object_notice_flag(o_ptr, flag); /* XXX Eddie should this go before noticing the flag to avoid learning twice? */ if (EASY_LEARN && object_is_jewelry(o_ptr)) { /* XXX Eddie EASY_LEARN Possible concern: gets =teleportation just from +2 speed */ object_flavor_aware(o_ptr); object_check_for_ident(o_ptr); } /* Message */ if (!streq(msgs[flag], "")) msg_format(msgs[flag], o_name); } else { /* Notice that flag is absent */ object_notice_flag(o_ptr, flag); } /* XXX Eddie should not need this, should be done in noticing, but will remove later */ object_check_for_ident(o_ptr); } return; }
/** * Mark as object as fully known, a.k.a identified. * Mark as object as fully known, a.k.a identified. * * \param o_ptr is the object to mark as identified */ void object_notice_everything(object_type *o_ptr) { artifact_type *a_ptr = artifact_of(o_ptr); /* The object is "empty" */ o_ptr->ident &= ~(IDENT_EMPTY); /* Mark as known */ object_flavor_aware(o_ptr); object_add_ident_flags(o_ptr, IDENTS_SET_BY_IDENTIFY); /* Artifact has now been seen */ if (a_ptr && !(o_ptr->ident & IDENT_FAKE)) { a_ptr->seen = a_ptr->everseen = TRUE; history_add_artifact(o_ptr->name1, TRUE, TRUE); } /* Know all flags there are to be known */ object_know_all_flags(o_ptr); }
/** * Add an item to the players inventory. * * If the new item can combine with an existing item in the inventory, * it will do so, using object_similar() and object_absorb(), else, * the item will be placed into the first available gear array index. * * This function can be used to "over-fill" the player's pack, but only * once, and such an action must trigger the "overflow" code immediately. * Note that when the pack is being "over-filled", the new item must be * placed into the "overflow" slot, and the "overflow" must take place * before the pack is reordered, but (optionally) after the pack is * combined. This may be tricky. See "dungeon.c" for info. * * Note that this code removes any location information from the object once * it is placed into the inventory, but takes no responsibility for removing * the object from any other pile it was in. */ void inven_carry(struct player *p, struct object *obj, bool absorb, bool message) { struct object *gear_obj; char o_name[80]; /* Check for combining, if appropriate */ if (absorb) { for (gear_obj = p->gear; gear_obj; gear_obj = gear_obj->next) { /* Can't stack equipment */ if (object_is_equipped(p->body, gear_obj)) continue; /* Check if the two items can be combined */ if (object_similar(gear_obj, obj, OSTACK_PACK)) { /* Increase the weight */ p->upkeep->total_weight += (obj->number * obj->weight); /* Combine the items, and their known versions */ object_absorb(gear_obj->known, obj->known); obj->known = NULL; object_absorb(gear_obj, obj); /* Describe the combined object */ object_desc(o_name, sizeof(o_name), gear_obj, ODESC_PREFIX | ODESC_FULL); /* Recalculate bonuses */ p->upkeep->update |= (PU_BONUS | PU_INVEN); /* Redraw stuff */ p->upkeep->redraw |= (PR_INVEN); /* Inventory will need updating */ update_stuff(player); /* Optionally, display a message */ if (message) msg("You have %s (%c).", o_name, gear_to_label(gear_obj)); /* Sound for quiver objects */ if (object_is_in_quiver(p, gear_obj)) sound(MSG_QUIVER); /* Success */ return; } } } /* Paranoia */ assert(pack_slots_used(p) <= z_info->pack_size); /* Add to the end of the list */ gear_insert_end(obj); /* Apply an autoinscription */ apply_autoinscription(obj); /* Remove cave object details */ obj->held_m_idx = 0; obj->iy = obj->ix = 0; obj->known->iy = obj->known->ix = 0; /* Update the inventory */ p->upkeep->total_weight += (obj->number * obj->weight); p->upkeep->update |= (PU_BONUS | PU_INVEN); p->upkeep->notice |= (PN_COMBINE); p->upkeep->redraw |= (PR_INVEN); /* Inventory will need updating */ update_stuff(player); /* Hobbits ID mushrooms on pickup, gnomes ID wands and staffs on pickup */ if (!object_flavor_is_aware(obj)) { if (player_has(player, PF_KNOW_MUSHROOM) && tval_is_mushroom(obj)) { object_flavor_aware(obj); msg("Mushrooms for breakfast!"); } else if (player_has(player, PF_KNOW_ZAPPER) && tval_is_zapper(obj)) object_flavor_aware(obj); } /* Optionally, display a message */ if (message) { /* Describe the object */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); /* Message */ msg("You have %s (%c).", o_name, gear_to_label(obj)); } /* Sound for quiver objects */ if (object_is_in_quiver(p, obj)) sound(MSG_QUIVER); }
/* * Use an object the right way. * * There may be a BIG problem with any "effect" that can cause "changes" * to the inventory. For example, a "scroll of recharging" can cause * a wand/staff to "disappear", moving the inventory up. Luckily, the * scrolls all appear BEFORE the staffs/wands, so this is not a problem. * But, for example, a "staff of recharging" could cause MAJOR problems. * In such a case, it will be best to either (1) "postpone" the effect * until the end of the function, or (2) "change" the effect, say, into * giving a staff "negative" charges, or "turning a staff into a stick". * It seems as though a "rod of recharging" might in fact cause problems. * The basic problem is that the act of recharging (and destroying) an * item causes the inducer of that action to "move", causing "o_ptr" to * no longer point at the correct item, with horrifying results. */ void do_cmd_use(cmd_code code, cmd_arg args[]) { int item = args[0].item; object_type *o_ptr = object_from_item_idx(item); int effect; bool ident = FALSE, used = FALSE; bool was_aware = object_flavor_is_aware(o_ptr); int dir = 5; int px = p_ptr->px, py = p_ptr->py; int snd, boost, level; use_type use; int items_allowed = 0; /* Determine how this item is used. */ if (obj_is_rod(o_ptr)) { if (!obj_can_zap(o_ptr)) { msg("That rod is still charging."); return; } use = USE_TIMEOUT; snd = MSG_ZAP_ROD; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_wand(o_ptr)) { if (!obj_has_charges(o_ptr)) { msg("That wand has no charges."); return; } use = USE_CHARGE; snd = MSG_ZAP_ROD; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_staff(o_ptr)) { if (!obj_has_charges(o_ptr)) { msg("That staff has no charges."); return; } use = USE_CHARGE; snd = MSG_USE_STAFF; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_food(o_ptr)) { use = USE_SINGLE; snd = MSG_EAT; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_potion(o_ptr)) { use = USE_SINGLE; snd = MSG_QUAFF; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_scroll(o_ptr)) { /* Check player can use scroll */ if (!player_can_read()) return; use = USE_SINGLE; snd = MSG_GENERIC; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_activatable(o_ptr)) { if (!obj_can_activate(o_ptr)) { msg("That item is still charging."); return; } use = USE_TIMEOUT; snd = MSG_ACT_ARTIFACT; items_allowed = USE_EQUIP; } else { msg("The item cannot be used at the moment"); } /* Check if item is within player's reach. */ if (items_allowed == 0 || !item_is_available(item, NULL, items_allowed)) { msg("You cannot use that item from its current location."); return; } /* track the object used */ track_object(item); /* Figure out effect to use */ effect = object_effect(o_ptr); /* If the item requires a direction, get one (allow cancelling) */ if (obj_needs_aim(o_ptr)) dir = args[1].direction; /* Check for use if necessary, and execute the effect */ if ((use != USE_CHARGE && use != USE_TIMEOUT) || check_devices(o_ptr)) { int beam = beam_chance(o_ptr->tval); /* Special message for artifacts */ if (o_ptr->artifact) { msgt(snd, "You activate it."); if (o_ptr->artifact->effect_msg) activation_message(o_ptr, o_ptr->artifact->effect_msg); level = o_ptr->artifact->level; } else { /* Make a noise! */ sound(snd); level = o_ptr->kind->level; } /* A bit of a hack to make ID work better. -- Check for "obvious" effects beforehand. */ if (effect_obvious(effect)) object_flavor_aware(o_ptr); /* Boost damage effects if skill > difficulty */ boost = MAX(p_ptr->state.skills[SKILL_DEVICE] - level, 0); /* Do effect */ used = effect_do(effect, &ident, was_aware, dir, beam, boost); /* Quit if the item wasn't used and no knowledge was gained */ if (!used && (was_aware || !ident)) return; } /* If the item is a null pointer or has been wiped, be done now */ if (!o_ptr || !o_ptr->kind) return; if (ident) object_notice_effect(o_ptr); /* Food feeds the player */ if (o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION) (void)set_food(p_ptr->food + o_ptr->pval[DEFAULT_PVAL]); /* Use the turn */ p_ptr->energy_use = 100; /* Mark as tried and redisplay */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); p_ptr->redraw |= (PR_INVEN | PR_EQUIP | PR_OBJECT); /* * If the player becomes aware of the item's function, then mark it as * aware and reward the player with some experience. Otherwise, mark * it as "tried". */ if (ident && !was_aware) { /* Object level */ int lev = o_ptr->kind->level; object_flavor_aware(o_ptr); if (o_ptr->tval == TV_ROD) object_notice_everything(o_ptr); player_exp_gain(p_ptr, (lev + (p_ptr->lev / 2)) / p_ptr->lev); p_ptr->notice |= PN_SQUELCH; } else if (used) { object_flavor_tried(o_ptr); } /* If there are no more of the item left, then we're done. */ if (!o_ptr->number) return; /* Chargeables act differently to single-used items when not used up */ if (used && use == USE_CHARGE) { /* Use a single charge */ o_ptr->pval[DEFAULT_PVAL]--; /* Describe charges */ if (item >= 0) inven_item_charges(item); else floor_item_charges(0 - item); } else if (used && use == USE_TIMEOUT) { /* Artifacts use their own special field */ if (o_ptr->artifact) o_ptr->timeout = randcalc(o_ptr->artifact->time, 0, RANDOMISE); else o_ptr->timeout += randcalc(o_ptr->kind->time, 0, RANDOMISE); } else if (used && use == USE_SINGLE) { /* Destroy a potion in the pack */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Destroy a potion on the floor */ else { floor_item_increase(0 - item, -1); floor_item_describe(0 - item); floor_item_optimize(0 - item); } } /* Hack to make Glyph of Warding work properly */ if (cave->feat[py][px] == FEAT_GLYPH) { /* Push objects off the grid */ if (cave->o_idx[py][px]) push_object(py, px); } }
/* XXX Eddie should messages be adhoc all over the place? perhaps the main * loop should check for change in inventory/wieldeds and all messages be * printed from one place */ void object_notice_on_wield(object_type *o_ptr) { bitflag f[OF_SIZE], obvious_mask[OF_SIZE]; bool obvious = FALSE; const slay_t *s_ptr; flags_init(obvious_mask, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); /* Save time of wield for later */ object_last_wield = turn; /* Only deal with un-ID'd items */ if (object_is_known(o_ptr)) return; /* Wear it */ object_flavor_tried(o_ptr); if (object_add_ident_flags(o_ptr, IDENT_WORN)) object_check_for_ident(o_ptr); if (obj_is_light(o_ptr) && ego_item_p(o_ptr)) object_notice_ego(o_ptr); if (object_flavor_is_aware(o_ptr) && easy_know(o_ptr)) { object_notice_everything(o_ptr); return; } /* Automatically sense artifacts upon wield */ object_sense_artifact(o_ptr); /* Note artifacts when found */ if (artifact_p(o_ptr)) history_add_artifact(o_ptr->name1, object_is_known(o_ptr), TRUE); /* special case FA, needed at least for mages wielding gloves */ if (object_FA_would_be_obvious(o_ptr)) of_on(obvious_mask, OF_FREE_ACT); /* Learn about obvious flags */ of_union(o_ptr->known_flags, obvious_mask); /* Extract the flags */ object_flags(o_ptr, f); /* Find obvious things (disregarding curses) */ flags_clear(obvious_mask, OF_SIZE, OF_CURSE_MASK, FLAG_END); if (of_is_inter(f, obvious_mask)) obvious = TRUE; flags_init(obvious_mask, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); /* XXX Eddie should these next NOT call object_check_for_ident due to worries about repairing? */ /* XXX Eddie this is a small hack, but jewelry with anything noticeable really is obvious */ /* XXX Eddie learn =soulkeeping vs =bodykeeping when notice sustain_str */ if (object_is_jewelry(o_ptr)) { /* Learn the flavor of jewelry with obvious flags */ if (EASY_LEARN && obvious) object_flavor_aware(o_ptr); /* Learn all flags on any aware non-artifact jewelry */ if (object_flavor_is_aware(o_ptr) && !artifact_p(o_ptr)) object_know_all_flags(o_ptr); } object_check_for_ident(o_ptr); if (!obvious) return; /* Messages */ for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++) { if (of_has(f, s_ptr->slay_flag) && s_ptr->brand) { char o_name[40]; object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); msg_format("Your %s %s!", o_name, s_ptr->active_verb); } } /* XXX Eddie need to add stealth here, also need to assert/double-check everything is covered */ if (of_has(f, OF_STR)) msg_format("You feel %s!", o_ptr->pval > 0 ? "stronger" : "weaker"); if (of_has(f, OF_INT)) msg_format("You feel %s!", o_ptr->pval > 0 ? "smarter" : "more stupid"); if (of_has(f, OF_WIS)) msg_format("You feel %s!", o_ptr->pval > 0 ? "wiser" : "more naive"); if (of_has(f, OF_DEX)) msg_format("You feel %s!", o_ptr->pval > 0 ? "more dextrous" : "clumsier"); if (of_has(f, OF_CON)) msg_format("You feel %s!", o_ptr->pval > 0 ? "healthier" : "sicklier"); if (of_has(f, OF_CHR)) msg_format("You feel %s!", o_ptr->pval > 0 ? "cuter" : "uglier"); if (of_has(f, OF_SPEED)) msg_format("You feel strangely %s.", o_ptr->pval > 0 ? "quick" : "sluggish"); if (flags_test(f, OF_SIZE, OF_BLOWS, OF_SHOTS, FLAG_END)) msg_format("Your hands %s", o_ptr->pval > 0 ? "tingle!" : "ache."); if (of_has(f, OF_INFRA)) msg_format("Your eyes tingle."); if (of_has(f, OF_LIGHT)) msg_print("It glows!"); if (of_has(f, OF_TELEPATHY)) msg_print("Your mind feels strangely sharper!"); /* WARNING -- masking f by obvious mask -- this should be at the end of this function */ flags_mask(f, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); /* learn the ego on any obvious brand or slay */ if (EASY_LEARN && ego_item_p(o_ptr) && obvious && flags_test(f, OF_SIZE, OF_ALL_SLAY_MASK, FLAG_END)) object_notice_ego(o_ptr); /* Remember the flags */ object_notice_sensing(o_ptr); /* XXX Eddie should we check_for_ident here? */ }
/** * Add an item to the players inventory. * * If the new item can combine with an existing item in the inventory, * it will do so, using object_similar() and object_absorb(), else, * the item will be placed into the first available gear array index. * * This function can be used to "over-fill" the player's pack, but only * once, and such an action must trigger the "overflow" code immediately. * Note that when the pack is being "over-filled", the new item must be * placed into the "overflow" slot, and the "overflow" must take place * before the pack is reordered, but (optionally) after the pack is * combined. This may be tricky. See "dungeon.c" for info. * * Note that this code removes any location information from the object once * it is placed into the inventory, but takes no responsibility for removing * the object from any other pile it was in. */ void inven_carry(struct player *p, struct object *obj, bool absorb, bool message) { bool combining = false; /* Check for combining, if appropriate */ if (absorb) { struct object *combine_item = NULL; struct object *gear_obj = p->gear; while (combine_item == false && gear_obj) { if (!object_is_equipped(p->body, gear_obj) && object_similar(gear_obj, obj, OSTACK_PACK)) { combine_item = gear_obj; } gear_obj = gear_obj->next; } if (combine_item) { /* Increase the weight */ p->upkeep->total_weight += (obj->number * obj->weight); /* Combine the items, and their known versions */ object_absorb(combine_item->known, obj->known); obj->known = NULL; object_absorb(combine_item, obj); obj = combine_item; combining = true; } } /* We didn't manage the find an object to combine with */ if (!combining) { /* Paranoia */ assert(pack_slots_used(p) <= z_info->pack_size); gear_insert_end(obj); apply_autoinscription(obj); /* Remove cave object details */ obj->held_m_idx = 0; obj->grid = loc(0, 0); obj->known->grid = loc(0, 0); /* Update the inventory */ p->upkeep->total_weight += (obj->number * obj->weight); p->upkeep->notice |= (PN_COMBINE); /* Hobbits ID mushrooms on pickup, gnomes ID wands and staffs on pickup */ if (!object_flavor_is_aware(obj)) { if (player_has(player, PF_KNOW_MUSHROOM) && tval_is_mushroom(obj)) { object_flavor_aware(obj); msg("Mushrooms for breakfast!"); } else if (player_has(player, PF_KNOW_ZAPPER) && tval_is_zapper(obj)) object_flavor_aware(obj); } } p->upkeep->update |= (PU_BONUS | PU_INVEN); p->upkeep->redraw |= (PR_INVEN); update_stuff(player); if (message) { char o_name[80]; object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); msg("You have %s (%c).", o_name, gear_to_label(obj)); } if (object_is_in_quiver(p, obj)) sound(MSG_QUIVER); }