/* * Change the quantity of an item */ static void wiz_quantity_item(object_type *o_ptr, bool carried) { int tmp_int; char tmp_val[3]; /* Never duplicate artifacts */ if (o_ptr->artifact) return; /* Default */ strnfmt(tmp_val, sizeof(tmp_val), "%d", o_ptr->number); /* Query */ if (get_string("Quantity: ", tmp_val, 3)) { /* Extract */ tmp_int = atoi(tmp_val); /* Paranoia */ if (tmp_int < 1) tmp_int = 1; if (tmp_int > 99) tmp_int = 99; /* Adjust total weight being carried */ if (carried) { /* Remove the weight of the old number of objects */ p_ptr->total_weight -= (o_ptr->number * o_ptr->weight); /* Add the weight of the new number of objects */ p_ptr->total_weight += (tmp_int * o_ptr->weight); } /* Adjust charges/timeouts for devices */ reduce_charges(o_ptr, (o_ptr->number - tmp_int)); /* Accept modifications */ o_ptr->number = tmp_int; } }
/* * Destroy an item */ void do_cmd_destroy(void) { int item, amt = 1; int old_number; bool force = FALSE; object_type *o_ptr; object_type forge; object_type *q_ptr = &forge; bool is_equipped = FALSE; char o_name[MAX_NLEN]; char out_val[MAX_NLEN+40]; cptr q, s; int mode = USE_INVEN | USE_FLOOR; if (p_ptr->pclass == CLASS_RUNE_KNIGHT) mode |= USE_EQUIP; if (p_ptr->special_defense & KATA_MUSOU) { set_action(ACTION_NONE); } /* Hack -- force destruction */ if (command_arg > 0) force = TRUE; /* Get an item */ q = "Destroy which item? "; s = "You have nothing to destroy."; if (!get_item(&item, q, s, mode)) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; is_equipped = equip_is_valid_slot(item); } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Hack for Rune Knight: They can destroy worn equipment, but only if it has the Sacrifice rune. get_item() is not smart enough to handle this restriction ... */ if (is_equipped && o_ptr->rune != RUNE_SACRIFICE) { msg_print("You must first remove that item before destroying it."); return; } /* Verify unless quantity given beforehand */ if (!force && (confirm_destroy || (object_value(o_ptr) > 0))) { object_desc(o_name, o_ptr, OD_OMIT_PREFIX); /* Make a verification */ sprintf(out_val, "Really destroy %s? [y/n/Auto]", o_name); msg_print(NULL); /* HACK : Add the line to message buffer */ message_add(out_val); p_ptr->window |= (PW_MESSAGE); window_stuff(); /* Get an acceptable answer */ while (TRUE) { char i; /* Prompt */ prt(out_val, 0, 0); i = inkey(); /* Erase the prompt */ prt("", 0, 0); if (i == 'y' || i == 'Y') { break; } if (i == ESCAPE || i == 'n' || i == 'N') { /* Cancel */ return; } if (i == 'A') { /* Add an auto-destroy preference line */ if (autopick_autoregister(o_ptr)) { /* Auto-destroy it */ autopick_alter_item(item, TRUE); } /* The object is already destroyed. */ return; } } /* while (TRUE) */ } /* See how many items */ if (o_ptr->number > 1) { /* Get a quantity */ amt = get_quantity(NULL, o_ptr->number); /* Allow user abort */ if (amt <= 0) return; } /* Describe the object */ old_number = o_ptr->number; o_ptr->number = amt; object_desc(o_name, o_ptr, 0); o_ptr->number = old_number; /* Take a turn */ energy_use = 100; /* Artifacts cannot be destroyed */ if (!can_player_destroy_object(o_ptr)) { energy_use = 0; /* Message */ msg_format("You cannot destroy %s.", o_name); /* Done */ return; } object_copy(q_ptr, o_ptr); stats_on_p_destroy(o_ptr, amt); if (prace_is_(RACE_MON_JELLY)) jelly_eat_object(o_ptr); else if (prace_is_(RACE_MON_SWORD) && object_is_melee_weapon(o_ptr)) sword_absorb_object(o_ptr); else if (prace_is_(RACE_MON_RING) && object_is_jewelry(o_ptr)) ring_absorb_object(o_ptr); else msg_format("You destroy %s.", o_name); if (o_ptr->rune == RUNE_SACRIFICE) { int add_hp = is_equipped ? p_ptr->mhp : p_ptr->mhp/3; int add_sp = is_equipped ? p_ptr->msp : p_ptr->msp/3; msg_print("You feel a surge of wondrous power enter your body."); p_ptr->chp = MIN(p_ptr->mhp, p_ptr->chp + add_hp); p_ptr->chp_frac = 0; p_ptr->csp = MIN(p_ptr->msp, p_ptr->csp + add_sp); p_ptr->csp_frac = 0; p_ptr->redraw |= (PR_MANA); p_ptr->window |= (PW_PLAYER); p_ptr->window |= (PW_SPELL); p_ptr->redraw |= (PR_HP); if (is_equipped) { blast_object(o_ptr); o_ptr->curse_flags = TRC_HEAVY_CURSE; } } else if (is_equipped) blast_object(o_ptr); sound(SOUND_DESTITEM); /* Reduce the charges of rods/wands */ reduce_charges(o_ptr, amt); /* Eliminate the item (from the pack) */ if (item >= 0) { if (!is_equipped) { inven_item_increase(item, -amt); inven_item_describe(item); inven_item_optimize(item); } } /* Eliminate the item (from the floor) */ else { floor_item_increase(0 - item, -amt); floor_item_describe(0 - item); floor_item_optimize(0 - item); } if ( p_ptr->pclass == CLASS_NECROMANCER && (q_ptr->tval == TV_LIFE_BOOK || q_ptr->tval == TV_CRUSADE_BOOK) ) { int sp = 0; int osp = p_ptr->csp; switch (q_ptr->sval) { case 0: sp = 10; break; case 1: sp = 25; break; case 2: sp = 100; break; case 3: sp = 666; break; } p_ptr->csp += sp; if (p_ptr->csp >= p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; } if (p_ptr->csp > osp) msg_print("You feel your head clear."); p_ptr->redraw |= (PR_MANA); } if (high_level_book(q_ptr)) { bool gain_expr = FALSE; if (p_ptr->prace == RACE_ANDROID) { } else if ((p_ptr->pclass == CLASS_WARRIOR) || (p_ptr->pclass == CLASS_BERSERKER)) { gain_expr = TRUE; } else if (p_ptr->pclass == CLASS_PALADIN) { if (is_good_realm(p_ptr->realm1)) { if (!is_good_realm(tval2realm(q_ptr->tval))) gain_expr = TRUE; } else { if (is_good_realm(tval2realm(q_ptr->tval))) gain_expr = TRUE; } } if (gain_expr && (p_ptr->exp < PY_MAX_EXP)) { s32b tester_exp = p_ptr->max_exp / 20; if (tester_exp > 10000) tester_exp = 10000; if (q_ptr->sval < 3) tester_exp /= 4; if (tester_exp<1) tester_exp = 1; msg_print("You feel more experienced."); gain_exp(tester_exp * amt); } } if (high_level_book(q_ptr) && q_ptr->tval == TV_LIFE_BOOK) { virtue_add(VIRTUE_UNLIFE, 1); virtue_add(VIRTUE_VITALITY, -1); } else if ( high_level_book(q_ptr) && (q_ptr->tval == TV_DEATH_BOOK || q_ptr->tval == TV_NECROMANCY_BOOK) ) { virtue_add(VIRTUE_UNLIFE, -1); virtue_add(VIRTUE_VITALITY, 1); } if (q_ptr->to_a || q_ptr->to_h || q_ptr->to_d) virtue_add(VIRTUE_ENCHANTMENT, -1); if (object_value_real(q_ptr) > 30000) virtue_add(VIRTUE_SACRIFICE, 2); else if (object_value_real(q_ptr) > 10000) virtue_add(VIRTUE_SACRIFICE, 1); if (q_ptr->to_a != 0 || q_ptr->to_d != 0 || q_ptr->to_h != 0) virtue_add(VIRTUE_HARMONY, 1); if (equip_is_valid_slot(item)) calc_android_exp(); }
/** * Destroys a type of item on a given percent chance. * The chance 'cperc' is in hundredths of a percent (1-in-10000) * Note that missiles are no longer necessarily all destroyed * * Returns number of items destroyed. */ int inven_damage(struct player *p, int type, int cperc) { int j, k, amt; struct object *obj; char o_name[80]; bool damage; /* No chance means no damage */ if (cperc <= 0) return 0; /* Count the casualties */ k = 0; /* Scan through the gear */ for (obj = p->gear; obj; obj = obj->next) { if (object_is_equipped(p->body, obj)) continue; /* Hack -- for now, skip artifacts */ if (obj->artifact) continue; /* Give this item slot a shot at death if it is vulnerable */ if ((obj->el_info[type].flags & EL_INFO_HATES) && !(obj->el_info[type].flags & EL_INFO_IGNORE)) { /* Chance to destroy this item */ int chance = cperc; /* Track if it is damaged instead of destroyed */ damage = FALSE; /* Analyze the type to see if we just damage it * - we also check for rods to reduce chance */ if (tval_is_weapon(obj) && !tval_is_ammo(obj)) { /* Chance to damage it */ if (randint0(10000) < cperc) { /* Damage the item */ obj->to_h--; obj->to_d--; /* Damaged! */ damage = TRUE; } else continue; } else if (tval_is_armor(obj)) { /* Chance to damage it */ if (randint0(10000) < cperc) { /* Damage the item */ obj->to_a--; /* Damaged! */ damage = TRUE; } else continue; } else if (tval_is_rod(obj)) { chance = (chance / 4); } /* Damage instead of destroy */ if (damage) { p->upkeep->update |= (PU_BONUS); p->upkeep->redraw |= (PR_EQUIP); /* Casualty count */ amt = obj->number; } else /* ... or count the casualties */ for (amt = j = 0; j < obj->number; ++j) if (randint0(10000) < chance) amt++; /* Some casualities */ if (amt) { struct object *destroyed; bool none_left = FALSE; /* Get a description */ object_desc(o_name, sizeof(o_name), obj, ODESC_BASE); /* Message */ msgt(MSG_DESTROY, "%sour %s (%c) %s %s!", ((obj->number > 1) ? ((amt == obj->number) ? "All of y" : (amt > 1 ? "Some of y" : "One of y")) : "Y"), o_name, gear_to_label(obj), ((amt > 1) ? "were" : "was"), (damage ? "damaged" : "destroyed")); /* Damage already done? */ if (damage) continue; /* Reduce charges if some devices are destroyed */ reduce_charges(obj, amt); /* Destroy "amt" items */ destroyed = gear_object_for_use(obj, amt, FALSE, &none_left); object_delete(&destroyed); /* Count the casualties */ k += amt; } } } /* Return the casualty count */ return (k); }
/* * Destroy an item */ void do_cmd_destroy(void) { int item, amt = 1; int old_number; bool force = FALSE; object_type *o_ptr; char o_name[MAX_NLEN]; char out_val[160]; cptr q, s; /* Hack -- force destruction */ if (command_arg > 0) force = TRUE; /* Get an item */ #ifdef JP q = "どのアイテムを壊しますか? "; s = "壊せるアイテムを持っていない。"; #else q = "Destroy which item? "; s = "You have nothing to destroy."; #endif 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]; } /* Verify unless quantity given */ if (!force && (!(auto_destroy && (object_value(o_ptr) < 1)))) { object_desc(o_name, o_ptr, OD_OMIT_PREFIX); /* Make a verification */ sprintf(out_val, #ifdef JP "本当に%sを壊しますか? [y/n/Auto]", #else "Really destroy %s? [y/n/Auto]", #endif o_name); msg_print(NULL); /* HACK : Add the line to message buffer */ message_add(out_val); p_ptr->window |= (PW_MESSAGE); window_stuff(); /* Get an acceptable answer */ while (TRUE) { char i; /* Prompt */ prt(out_val, 0, 0); i = inkey(); /* Erase the prompt */ prt("", 0, 0); if (i == 'y' || i == 'Y') { break; } if (i == ESCAPE || i == 'n' || i == 'N') { /* Cancel */ return; } if (i == 'A') { /* Add an auto-destroy preference line */ if (autopick_autoregister(o_ptr)) { /* Auto-destroy it */ autopick_alter_item(item, TRUE); } /* The object is already destroyed. */ return; } } /* while (TRUE) */ } /* See how many items */ if (o_ptr->number > 1) { /* Get a quantity */ amt = get_quantity(NULL, o_ptr->number); /* Allow user abort */ if (amt <= 0) return; } /* Describe the object */ old_number = o_ptr->number; o_ptr->number = amt; object_desc(o_name, o_ptr, 0); o_ptr->number = old_number; /* Take a turn */ energy_use = 100; /* Can the player destroy the object? */ if (!can_player_destroy_object(o_ptr)) { /* Don't take a turn */ energy_use = 0; /* Message */ #ifdef JP msg_format("%sは破壊不可能だ。", o_name); #else msg_format("You cannot destroy %s.", o_name); #endif /* Done */ return; } /* Message */ #ifdef JP msg_format("%sを壊した。", o_name); #else msg_format("You destroy %s.", o_name); #endif sound(SOUND_DESTROY); if (high_level_book(o_ptr)) { bool gain_expr = FALSE; if (p_ptr->pclass == CLASS_WARRIOR) { gain_expr = TRUE; } else if (p_ptr->pclass == CLASS_PALADIN) { if (p_ptr->realm1 == REALM_LIFE) { if (o_ptr->tval != TV_LIFE_BOOK) gain_expr = TRUE; } else { if (o_ptr->tval == TV_LIFE_BOOK) gain_expr = TRUE; } } if (gain_expr && (p_ptr->exp < PY_MAX_EXP)) { s32b tester_exp = p_ptr->max_exp / 20; if (tester_exp > 10000) tester_exp = 10000; if (o_ptr->sval < 3) tester_exp /= 4; if (tester_exp < 1) tester_exp = 1; #ifdef JP msg_print("更に経験を積んだような気がする。"); #else msg_print("You feel more experienced."); #endif gain_exp(tester_exp * amt); } } /* Reduce the charges of rods/wands */ reduce_charges(o_ptr, amt); /* Eliminate the item (from the pack) */ if (item >= 0) { inven_item_increase(item, -amt); inven_item_describe(item); inven_item_optimize(item); } /* Eliminate the item (from the floor) */ else { floor_item_increase(0 - item, -amt); floor_item_describe(0 - item); floor_item_optimize(0 - item); } }