/* * Aim a wand (from the pack or floor). * * Use a single charge from a single item. * Handle "unstacking" in a logical manner. * * For simplicity, you cannot use a stack of items from the * ground. This would require too much nasty code. * * There are no wands which can "destroy" themselves, in the inventory * or on the ground, so we can ignore this possibility. Note that this * required giving "wand of wonder" the ability to ignore destruction * by electric balls. * * All wands can be "cancelled" at the "Direction?" prompt for free. * * Note that the basic "bolt" wands do slightly less damage than the * basic "bolt" rods, but the basic "ball" wands do the same damage * as the basic "ball" rods. */ void do_cmd_aim_wand(void) { int item, lev; bool ident; object_type *o_ptr; cptr q, s; /* Restrict choices to wands */ item_tester_tval = TV_WAND; /* Get an item */ q = "Aim which wand? "; s = "You have no wand to aim."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Mega-Hack -- refuse to aim a pile from the ground */ if ((item < 0) && (o_ptr->number > 1)) { msg_print("You must first pick up the wands."); return; } /* Aim the wand */ if (!use_object(o_ptr, &ident)) return; /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Mark it as tried */ object_tried(o_ptr); /* Object level */ lev = k_info[o_ptr->k_idx].level; /* Apply identification */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* Use a single charge */ o_ptr->pval--; /* Hack -- unstack if necessary */ if ((item >= 0) && (o_ptr->number > 1)) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Restore the charges */ o_ptr->pval++; /* Unstack the used item */ o_ptr->number--; p_ptr->total_weight -= i_ptr->weight; item = inven_carry(i_ptr); /* Message */ msg_print("You unstack your wand."); } /* Describe the charges in the pack */ if (item >= 0) { inven_item_charges(item); } /* Describe the charges on the floor */ else { floor_item_charges(0 - item); } }
/* * 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); } }
/* * Use a staff * * One charge of one staff disappears. * * Hack -- staffs of identify can be "cancelled". */ void do_cmd_use_staff(void) { int item, chance, lev; bool ident; object_type *o_ptr; bool use_charge; cptr q, s; /* Restrict choices to staves */ item_tester_tval = TV_STAFF; /* Get an item */ q = "Use which staff? "; s = "You have no staff to use."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Mega-Hack -- refuse to use a pile from the ground */ if ((item < 0) && (o_ptr->number > 1)) { msg_print("You must first pick up the staffs."); return; } /* Take a turn */ p_ptr->energy_use = 100; /* Not identified yet */ ident = FALSE; /* Extract the item level */ lev = k_info[o_ptr->k_idx].level; /* Base chance of success */ chance = p_ptr->skill_dev; /* Confusion hurts skill */ if (p_ptr->confused) chance = chance / 2; /* High level objects are harder */ chance = chance - ((lev > 50) ? 50 : lev); /* Give everyone a (slight) chance */ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) { chance = USE_DEVICE; } /* Roll for usage */ if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) { if (flush_failure) flush(); msg_print("You failed to use the staff properly."); return; } /* Notice empty staffs */ if (o_ptr->pval <= 0) { if (flush_failure) flush(); msg_print("The staff has no charges left."); o_ptr->ident |= (IDENT_EMPTY); p_ptr->notice |= (PN_COMBINE | PN_REORDER); p_ptr->window |= (PW_INVEN); return; } /* Sound */ sound(MSG_ZAP); /* Use the staff */ use_charge = use_object(o_ptr, &ident); /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Tried the item */ object_tried(o_ptr); /* An identification was made */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* Hack -- some uses are "free" */ if (!use_charge) return; /* Use a single charge */ o_ptr->pval--; /* XXX Hack -- unstack if necessary */ if ((item >= 0) && (o_ptr->number > 1)) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Restore the charges */ o_ptr->pval++; /* Unstack the used item */ o_ptr->number--; p_ptr->total_weight -= i_ptr->weight; item = inven_carry(i_ptr); /* Message */ msg_print("You unstack your staff."); } /* Describe charges in the pack */ if (item >= 0) { inven_item_charges(item); } /* Describe charges on the floor */ else { floor_item_charges(0 - item); } }