/* * 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_print("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_print("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_print("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_print("That item is still charging."); return; } use = USE_TIMEOUT; snd = MSG_ACT_ARTIFACT; items_allowed = USE_EQUIP; } else { msg_print("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_print("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)) { /* Special message for artifacts */ if (artifact_p(o_ptr)) { message(snd, 0, "You activate it."); if (a_info[o_ptr->name1].effect_msg) activation_message(o_ptr, a_info[o_ptr->name1].effect_msg); level = a_info[o_ptr->name1].level; } else { /* Make a noise! */ sound(snd); level = k_info[o_ptr->k_idx].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 = p_ptr->state.skills[SKILL_DEVICE] - level; if (boost < 0) boost = 0; /* Do effect */ used = effect_do(effect, &ident, was_aware, dir, beam_chance(o_ptr->tval), 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->k_idx <= 1) 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); /* 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 = k_info[o_ptr->k_idx].level; object_flavor_aware(o_ptr); if (o_ptr->tval == TV_ROD) object_notice_everything(o_ptr); gain_exp((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--; /* 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->name1) { const artifact_type *a_ptr = &a_info[o_ptr->name1]; o_ptr->timeout = randcalc(a_ptr->time, 0, RANDOMISE); } else { const object_kind *k_ptr = &k_info[o_ptr->k_idx]; o_ptr->timeout += randcalc(k_ptr->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) { /* Shift any objects to further away */ for (o_ptr = get_first_object(py, px); o_ptr; o_ptr = get_next_object(o_ptr)) { drop_near(o_ptr, 0, py, px, FALSE); } /* Delete the "moved" objects from their original position */ delete_object(py, px); } }
/* * Examine a grid, return a keypress. * * The "mode" argument contains the "TARGET_LOOK" bit flag, which * indicates that the "space" key should scan through the contents * of the grid, instead of simply returning immediately. This lets * the "look" command get complete information, without making the * "target" command annoying. * * The "info" argument contains the "commands" which should be shown * inside the "[xxx]" text. This string must never be empty, or grids * containing monsters will be displayed with an extra comma. * * Note that if a monster is in the grid, we update both the monster * recall info and the health bar info to track that monster. * * This function correctly handles multiple objects per grid, and objects * and terrain features in the same grid, though the latter never happens. * * This function must handle blindness/hallucination. */ static struct keypress target_set_interactive_aux(int y, int x, int mode) { s16b this_o_idx = 0, next_o_idx = 0; const char *s1, *s2, *s3; bool boring; int feat; int floor_list[MAX_FLOOR_STACK]; int floor_num; struct keypress query; char out_val[256]; char coords[20]; /* Describe the square location */ coords_desc(coords, sizeof(coords), y, x); /* Repeat forever */ while (1) { /* Paranoia */ query.code = ' '; /* Assume boring */ boring = TRUE; /* Default */ s1 = "You see "; s2 = ""; s3 = ""; /* The player */ if (cave->m_idx[y][x] < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Hack -- hallucination */ if (p_ptr->timed[TMD_IMAGE]) { const char *name = "something strange"; /* Display a message */ if (p_ptr->wizard) strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); else strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); /* Stop on everything but "return" */ if (query.code == '\n' || query.code == '\r') continue; return query; } /* Actual monsters */ if (cave->m_idx[y][x] > 0) { monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]); monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Visible */ if (m_ptr->ml && !m_ptr->unaware) { bool recall = FALSE; char m_name[80]; /* Not boring */ boring = FALSE; /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND2); /* Hack -- track this monster race */ monster_race_track(m_ptr->r_idx); /* Hack -- health bar for this monster */ health_track(p_ptr, cave->m_idx[y][x]); /* Hack -- handle stuff */ handle_stuff(); /* Interact */ while (1) { /* Recall */ if (recall) { /* Save screen */ screen_save(); /* Recall on screen */ screen_roff(m_ptr->r_idx); /* Command */ query = inkey(); /* Load screen */ screen_load(); } /* Normal */ else { char buf[80]; /* Describe the monster */ look_mon_desc(buf, sizeof(buf), cave->m_idx[y][x]); /* Describe, and prompt for recall */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s (%d:%d).", s1, s2, s3, m_name, buf, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s.", s1, s2, s3, m_name, buf, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ query = inkey(); } /* Normal commands */ if (query.code == 'r') recall = !recall; else break; } /* Stop on everything but "return"/"space" */ if (query.code != '\n' && query.code != '\r' && query.code != ' ') break; /* Sometimes stop at "space" key */ if ((query.code == ' ') && !(mode & (TARGET_LOOK))) break; /* Take account of gender */ if (rf_has(r_ptr->flags, RF_FEMALE)) s1 = "She is "; else if (rf_has(r_ptr->flags, RF_MALE)) s1 = "He is "; else s1 = "It is "; /* Use a preposition */ s2 = "carrying "; /* Scan all objects being carried */ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) { char o_name[80]; object_type *o_ptr; /* Get the object */ o_ptr = object_byid(this_o_idx); /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); /* Stop on everything but "return"/"space" */ if ((query.code != '\n') && (query.code != '\r') && (query.code != ' ')) break; /* Sometimes stop at "space" key */ if ((query.code == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (this_o_idx) break; /* Use a preposition */ s2 = "on "; } } /* Assume not floored */ floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), y, x, 0x02); /* Scan all marked objects in the grid */ if ((floor_num > 0) && (!(p_ptr->timed[TMD_BLIND]) || (y == p_ptr->py && x == p_ptr->px))) { /* Not boring */ boring = FALSE; track_object(-floor_list[0]); handle_stuff(); /* If there is more than one item... */ if (floor_num > 1) while (1) { /* Describe the pile */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s (%d:%d).", s1, s2, s3, floor_num, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s.", s1, s2, s3, floor_num, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); /* Display objects */ if (query.code == 'r') { int rdone = 0; int pos; while (!rdone) { /* Save screen */ screen_save(); /* Display */ show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD)); /* Describe the pile */ prt(out_val, 0, 0); query = inkey(); /* Load screen */ screen_load(); pos = query.code - 'a'; if (0 <= pos && pos < floor_num) { track_object(-floor_list[pos]); handle_stuff(); continue; } rdone = 1; } /* Now that the user's done with the display loop, let's */ /* the outer loop over again */ continue; } /* Done */ break; } /* Only one object to display */ else { char o_name[80]; /* Get the single object in the list */ object_type *o_ptr = object_byid(floor_list[0]); /* Not boring */ boring = FALSE; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); /* Stop on everything but "return"/"space" */ if ((query.code != '\n') && (query.code != '\r') && (query.code != ' ')) break; /* Sometimes stop at "space" key */ if ((query.code == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Plurals */ if (o_ptr->number != 1) s1 = "They are "; /* Preposition */ s2 = "on "; } } /* Double break */ if (this_o_idx) break; /* Feature (apply "mimic") */ feat = f_info[cave->feat[y][x]].mimic; /* Require knowledge about grid, or ability to see grid */ if (!(cave->info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x)) { /* Forget feature */ feat = FEAT_NONE; } /* Terrain feature if needed */ if (boring || (feat > FEAT_INVIS)) { const char *name = f_info[feat].name; /* Hack -- handle unknown grids */ if (feat == FEAT_NONE) name = "unknown grid"; /* Pick a prefix */ if (*s2 && (feat >= FEAT_DOOR_HEAD)) s2 = "in "; /* Pick proper indefinite article */ s3 = (is_a_vowel(name[0])) ? "an " : "a "; /* Hack -- special introduction for store doors */ if ((feat >= FEAT_SHOP_HEAD) && (feat <= FEAT_SHOP_TAIL)) { s3 = "the entrance to the "; } /* Display a message */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); /* Stop on everything but "return"/"space" */ if ((query.code != '\n') && (query.code != '\r') && (query.code != ' ')) break; } /* Stop on everything but "return" */ if ((query.code != '\n') && (query.code != '\r')) break; } /* Keep going */ return (query); }
GridDialog::GridDialog(int _y, int _x): NPPDialog() { y = _y; x = _x; dungeon_type *d_ptr = &dungeon_info[y][x]; int n = 0; bool drugged = (p_ptr->timed[TMD_IMAGE] > 0); central = new QWidget; QPointer<QVBoxLayout> lay1 = new QVBoxLayout; central->setLayout(lay1); this->setClient(central); // Do this after setting layout QPointer<QWidget> area2 = new QWidget; lay1->addWidget(area2); QPointer<QGridLayout> lay2 = new QGridLayout; lay2->setContentsMargins(0, 0, 0, 0); area2->setLayout(lay2); lay2->setColumnStretch(3, 1); QFont font = ui_main_window_font(); int col = 0; int row = 0; int m_idx = d_ptr->monster_idx; if (m_idx > 0 && mon_list[m_idx].ml && !drugged) { ++n; monster_type *m_ptr = mon_list + m_idx; monster_race *r_ptr = r_info + m_ptr->r_idx; QPointer<QLabel> lb = new QLabel(QString(" %1 ").arg(r_ptr->d_char)); lb->setStyleSheet(QString("background-color: black; color: %1;").arg(r_ptr->d_color.name())); lb->setFont(font); lay2->addWidget(lb, row, col++); QPixmap pix = ui_get_tile(r_ptr->tile_id, TRUE); QPointer<QLabel> lb2 = new QLabel; lb2->setPixmap(pix); lay2->addWidget(lb2, row, col++); int gain_m = calc_energy_gain(m_ptr->m_speed); int gain_p = calc_energy_gain(p_ptr->state.p_speed); QString msg = monster_desc(m_ptr, 0x08); if (p_ptr->is_wizard) { msg.append(QString(" - HP: %4 - Energy: %2 - Player energy: %3") .arg(gain_m).arg(gain_p).arg(m_ptr->hp)); } msg = capitalize_first(msg); QPointer<QPushButton> btn1 = new QPushButton(msg); QString item_id = QString("m%1").arg(m_idx); btn1->setObjectName(item_id); btn1->setStyleSheet("text-align: left;"); lay2->addWidget(btn1, row, col++); connect(btn1, SIGNAL(clicked()), this, SLOT(item_click())); monster_race_track(m_ptr->r_idx); ++row; } int o_idx = d_ptr->object_idx; bool tracked_item = FALSE; while (o_idx && !drugged) { object_type *o_ptr = o_list + o_idx; int cur_o_idx = o_idx; o_idx = o_ptr->next_o_idx; if (!o_ptr->marked) continue; if (!tracked_item) { track_object(-cur_o_idx); tracked_item = TRUE; } ++n; col = 0; object_kind *k_ptr = k_info + o_ptr->k_idx; QChar chr = k_ptr->get_char(); QColor color = k_ptr->get_color(); QString tile = k_ptr->get_tile_id(); QPointer<QLabel> lb = new QLabel(QString(" %1 ").arg(chr)); lb->setStyleSheet(QString("background-color: black; color: %1;").arg(color.name())); lb->setFont(font); lay2->addWidget(lb, row, col++); QPixmap pix = ui_get_tile(tile, TRUE); QPointer<QLabel> lb2 = new QLabel; lb2->setPixmap(pix); lay2->addWidget(lb2, row, col++); QString name = object_desc(o_ptr, ODESC_FULL | ODESC_PREFIX); name = capitalize_first(name); QPointer<QPushButton> btn1 = new QPushButton(name); QString item_id = QString("o%1").arg(cur_o_idx); btn1->setObjectName(item_id); btn1->setStyleSheet("text-align: left;"); lay2->addWidget(btn1, row, col++); connect(btn1, SIGNAL(clicked()), this, SLOT(item_click())); ++row; } if (d_ptr->cave_info & (CAVE_MARK | CAVE_SEEN)) { ++n; col = 0; int feat = d_ptr->feature_idx; feat = f_info[feat].f_mimic; feature_type *f_ptr = f_info + feat; QPointer<QLabel> lb = new QLabel(QString(" %1 ").arg(f_ptr->d_char)); lb->setStyleSheet(QString("background-color: black; color: %1;").arg(f_ptr->d_color.name())); lb->setFont(font); lay2->addWidget(lb, row, col++); QPixmap pix = ui_get_tile(f_ptr->tile_id, TRUE); QPointer<QLabel> lb2 = new QLabel; lb2->setPixmap(pix); lay2->addWidget(lb2, row, col++); QString name = feature_desc(feat, true, false); name = capitalize_first(name); QPointer<QPushButton> btn1 = new QPushButton(name); QString item_id = QString("f%1").arg(feat); btn1->setObjectName(item_id); btn1->setStyleSheet("text-align: left;"); lay2->addWidget(btn1, row, col++); connect(btn1, SIGNAL(clicked()), this, SLOT(item_click())); ++row; feature_kind_track(feat); } int x_idx = d_ptr->effect_idx; while (x_idx && (d_ptr->cave_info & (CAVE_MARK | CAVE_SEEN))) { effect_type *x_ptr = x_list + x_idx; x_idx = x_ptr->next_x_idx; if (x_ptr->x_flags & EF1_HIDDEN) continue; int feat = x_ptr->x_f_idx; if (!feat) continue; feat = f_info[feat].f_mimic; if (!feat) continue; feature_type *f_ptr = f_info + feat; col = 0; QPointer<QLabel> lb = new QLabel(QString(" %1 ").arg(f_ptr->d_char)); lb->setStyleSheet(QString("background-color: black; color: %1;").arg(f_ptr->d_color.name())); lb->setFont(font); lay2->addWidget(lb, row, col++); QPixmap pix = ui_get_tile(f_ptr->tile_id, TRUE); QPointer<QLabel> lb2 = new QLabel; lb2->setPixmap(pix); lay2->addWidget(lb2, row, col++); QString name = feature_desc(feat, true, false); name = capitalize_first(name); QPointer<QPushButton> btn1 = new QPushButton(name); QString item_id = QString("f%1").arg(feat); btn1->setObjectName(item_id); btn1->setStyleSheet("text-align: left;"); lay2->addWidget(btn1, row, col++); connect(btn1, SIGNAL(clicked()), this, SLOT(item_click())); ++n; ++row; } QSpacerItem *spacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding); lay2->addItem(spacer, row, 0); ++row; QPointer<QWidget> area3 = new QWidget; lay1->addWidget(area3); QPointer<QHBoxLayout> lay3 = new QHBoxLayout; lay3->setContentsMargins(0, 0, 0, 0); area3->setLayout(lay3); QSpacerItem *spacer2 = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed); lay3->addItem(spacer2); QPointer<QPushButton> btn_close = new QPushButton("Ok"); lay3->addWidget(btn_close); connect(btn_close, SIGNAL(clicked()), this, SLOT(reject())); this->clientSizeUpdated(); handle_stuff(); if (n > 0) { (this->findChildren<QPushButton *>().at(0))->setFocus(); this->exec(); } else message(tr("There is nothing to see here")); }
/* * Carry an object and delete it. */ static void py_pickup_aux(int o_idx, bool domsg) { int slot, quiver_slot = 0; char o_name[80]; object_type *o_ptr = object_byid(o_idx); /* Carry the object */ slot = inven_carry(p_ptr, o_ptr); /* Handle errors (paranoia) */ if (slot < 0) return; /* If we have picked up ammo which matches something in the quiver, note * that it so that we can wield it later (and suppress pick up message) */ if (obj_is_ammo(o_ptr)) { int i; for (i = QUIVER_START; i < QUIVER_END; i++) { if (!p_ptr->inventory[i].kind) continue; if (!object_similar(&p_ptr->inventory[i], o_ptr, OSTACK_QUIVER)) continue; quiver_slot = i; break; } } /* Get the new object */ o_ptr = &p_ptr->inventory[slot]; /* Set squelch status */ p_ptr->notice |= PN_SQUELCH; /* Automatically sense artifacts */ object_sense_artifact(o_ptr); /* Log artifacts if found */ if (o_ptr->artifact) history_add_artifact(o_ptr->artifact, object_is_known(o_ptr), TRUE); /* Optionally, display a message */ if (domsg && !quiver_slot) { /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Message */ msg("You have %s (%c).", o_name, index_to_label(slot)); } /* Update object_idx if necessary */ if (tracked_object_is(0 - o_idx)) { track_object(slot); } /* Delete the object */ delete_object_idx(o_idx); /* If we have a quiver slot that this ammo matches, use it */ if (quiver_slot) wield_item(o_ptr, slot, quiver_slot); }
/* * Wield or wear a single item from the pack or floor */ void wield_item(object_type *o_ptr, int item, int slot) { object_type object_type_body; object_type *i_ptr = &object_type_body; const char *fmt; char o_name[80]; bool combined_ammo = FALSE; bool track_wielded_item = FALSE; int num = 1; /* If we are stacking ammo in the quiver */ if (obj_is_ammo(o_ptr)) { num = o_ptr->number; combined_ammo = object_similar(o_ptr, &p_ptr->inventory[slot], OSTACK_QUIVER); } /* Take a turn */ p_ptr->energy_use = 100; /* Obtain local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = num; /* Update object_idx if necessary, once object is in slot */ if (p_ptr->object_idx == item) { track_wielded_item = TRUE; } /* Decrease the item (from the pack) */ if (item >= 0) { inven_item_increase(item, -num); inven_item_optimize(item); } /* Decrease the item (from the floor) */ else { floor_item_increase(0 - item, -num); floor_item_optimize(0 - item); } /* Get the wield slot */ o_ptr = &p_ptr->inventory[slot]; if (combined_ammo) { /* Add the new ammo to the already-quiver-ed ammo */ object_absorb(o_ptr, i_ptr); } else { /* Take off existing item */ if (o_ptr->kind) (void)inven_takeoff(slot, 255); /* If we are wielding ammo we may need to "open" the slot by shifting * later ammo up the quiver; this is because we already called the * inven_item_optimize() function. */ if (slot >= QUIVER_START) open_quiver_slot(slot); /* Wear the new stuff */ object_copy(o_ptr, i_ptr); /* Increment the equip counter by hand */ p_ptr->equip_cnt++; } /* Increase the weight */ p_ptr->total_weight += i_ptr->weight * num; /* Track object if necessary */ if (track_wielded_item) { track_object(slot); } /* Do any ID-on-wield */ object_notice_on_wield(o_ptr); /* Where is the item now */ if (slot == INVEN_WIELD) fmt = "You are wielding %s (%c)."; else if (slot == INVEN_BOW) fmt = "You are shooting with %s (%c)."; else if (slot == INVEN_LIGHT) fmt = "Your light source is %s (%c)."; else if (combined_ammo) fmt = "You combine %s in your quiver (%c)."; else if (slot >= QUIVER_START && slot < QUIVER_END) fmt = "You add %s to your quiver (%c)."; else fmt = "You are wearing %s (%c)."; /* Describe the result */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Message */ msgt(MSG_WIELD, fmt, o_name, index_to_label(slot)); /* Cursed! */ if (cursed_p(o_ptr->flags)) { /* Warn the player */ msgt(MSG_CURSED, "Oops! It feels deathly cold!"); /* Sense the object */ object_notice_curses(o_ptr); } /* Save quiver size */ save_quiver_size(p_ptr); /* See if we have to overflow the pack */ pack_overflow(); /* Recalculate bonuses, torch, mana */ p_ptr->notice |= PN_SORT_QUIVER; p_ptr->update |= (PU_BONUS | PU_TORCH | PU_MANA); p_ptr->redraw |= (PR_INVEN | PR_EQUIP); }
/** * Remove an amount of an object from the inventory or quiver, returning * a detached object which can be used. * * Optionally describe what remains. */ struct object *gear_object_for_use(struct object *obj, int num, bool message, bool *none_left) { struct object *usable; char name[80]; char label = gear_to_label(obj); bool artifact = (obj->known->artifact != NULL); /* Bounds check */ num = MIN(num, obj->number); /* Split off a usable object if necessary */ if (obj->number > num) { usable = object_split(obj, num); /* Change the weight */ player->upkeep->total_weight -= (num * obj->weight); if (message) { object_desc(name, sizeof(name), obj, ODESC_PREFIX | ODESC_FULL); } } else { if (message) { if (artifact) { object_desc(name, sizeof(name), obj, ODESC_FULL | ODESC_SINGULAR); } else { /* Describe zero amount */ obj->number = 0; object_desc(name, sizeof(name), obj, ODESC_PREFIX | ODESC_FULL); obj->number = num; } } /* We're using the entire stack */ usable = obj; gear_excise_object(usable); *none_left = true; /* Stop tracking item */ if (tracked_object_is(player->upkeep, obj)) track_object(player->upkeep, NULL); /* Inventory has changed, so disable repeat command */ cmd_disable_repeat(); } /* Housekeeping */ player->upkeep->update |= (PU_BONUS); player->upkeep->notice |= (PN_COMBINE); player->upkeep->redraw |= (PR_INVEN | PR_EQUIP); /* Print a message if desired */ if (message) { if (artifact) msg("You no longer have the %s (%c).", name, label); else msg("You have %s (%c).", name, label); } return usable; }