/** * Check if the given item is available for the player to use. */ bool item_is_available(struct object *obj) { if (object_is_carried(player, obj)) return true; if (cave && square_holds_object(cave, player->py, player->px, obj)) return true; return false; }
/** * Put an autoinscription on an object */ int apply_autoinscription(struct object *obj) { char o_name[80]; const char *note = obj ? get_autoinscription(obj->kind) : NULL; /* Don't inscribe unaware objects */ if (!note || !object_flavor_is_aware(obj)) return 0; /* Don't re-inscribe if it's already inscribed */ if (obj->note) return 0; /* Don't inscribe unless the player is carrying it */ if (!object_is_carried(player, obj)) return 0; /* Don't inscribe if ignored */ if (ignore_item_ok(obj)) return 0; /* Get an object description */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); if (note[0] != 0) obj->note = quark_add(note); else obj->note = 0; msg("You autoinscribe %s.", o_name); return 1; }
/** * Put an autoinscription on an object */ int apply_autoinscription(struct object *obj) { char o_name[80]; bool aware = obj->kind->aware; const char *note = obj ? get_autoinscription(obj->kind, aware) : NULL; /* Remove unaware inscription if aware */ if (aware && quark_str(obj->note) && quark_str(obj->kind->note_unaware) && streq(quark_str(obj->note), quark_str(obj->kind->note_unaware))) obj->note = 0; /* Make rune autoinscription go first, for now */ runes_autoinscribe(obj); /* No note - don't inscribe */ if (!note) return 0; /* Don't re-inscribe if it's already inscribed */ if (obj->note) return 0; /* Don't inscribe unless the player is carrying it */ if (!object_is_carried(player, obj)) return 0; /* Don't inscribe if ignored */ if (ignore_item_ok(obj)) return 0; /* Get an object description */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); if (note[0] != 0) obj->note = quark_add(note); else obj->note = 0; msg("You autoinscribe %s.", o_name); return 1; }
/** * Drop (some of) a non-cursed inventory/equipment item "near" the current * location * * There are two cases here - a single object or entire stack is being dropped, * or part of a stack is being split off and dropped */ void inven_drop(struct object *obj, int amt) { int py = player->py; int px = player->px; struct object *dropped; bool none_left = false; bool quiver = false; char name[80]; char label; /* Error check */ if (amt <= 0) return; /* Check it is still held, in case there were two drop commands queued * for this item. This is in theory not ideal, but in practice should * be safe. */ if (!object_is_carried(player, obj)) return; /* Get where the object is now */ label = gear_to_label(obj); /* Is it in the quiver? */ if (object_is_in_quiver(player, obj)) quiver = true; /* Not too many */ if (amt > obj->number) amt = obj->number; /* Take off equipment, don't combine */ if (object_is_equipped(player->body, obj)) inven_takeoff(obj); /* Get the object */ dropped = gear_object_for_use(obj, amt, false, &none_left); /* Describe the dropped object */ object_desc(name, sizeof(name), dropped, ODESC_PREFIX | ODESC_FULL); /* Message */ msg("You drop %s (%c).", name, label); /* Describe what's left */ if (dropped->artifact) { object_desc(name, sizeof(name), dropped, ODESC_FULL | ODESC_SINGULAR); msg("You no longer have the %s (%c).", name, label); } else if (none_left) { /* Play silly games to get the right description */ int number = dropped->number; dropped->number = 0; object_desc(name, sizeof(name), dropped, ODESC_PREFIX | ODESC_FULL); msg("You have %s (%c).", name, label); dropped->number = number; } else { object_desc(name, sizeof(name), obj, ODESC_PREFIX | ODESC_FULL); msg("You have %s (%c).", name, label); } /* Drop it near the player */ drop_near(cave, &dropped, 0, py, px, false); /* Sound for quiver objects */ if (quiver) sound(MSG_QUIVER); event_signal(EVENT_INVENTORY); event_signal(EVENT_EQUIPMENT); }
/** * Wield or wear a single item from the pack or floor */ void inven_wield(struct object *obj, int slot) { struct object *wielded, *old = player->body.slots[slot].obj; const char *fmt; char o_name[80]; bool dummy = false; /* Increase equipment counter if empty slot */ if (old == NULL) player->upkeep->equip_cnt++; /* Take a turn */ player->upkeep->energy_use = z_info->move_energy; /* It's either a gear object or a floor object */ if (object_is_carried(player, obj)) { /* Split off a new object if necessary */ if (obj->number > 1) { wielded = gear_object_for_use(obj, 1, false, &dummy); /* The new item needs new gear and known gear entries */ wielded->next = obj->next; obj->next = wielded; wielded->prev = obj; if (wielded->next) (wielded->next)->prev = wielded; wielded->known->next = obj->known->next; obj->known->next = wielded->known; wielded->known->prev = obj->known; if (wielded->known->next) (wielded->known->next)->prev = wielded->known; } else { /* Just use the object directly */ wielded = obj; } } else { /* Get a floor item and carry it */ wielded = floor_object_for_use(obj, 1, false, &dummy); inven_carry(player, wielded, false, false); } /* Wear the new stuff */ player->body.slots[slot].obj = wielded; /* Do any ID-on-wield */ object_learn_on_wield(player, wielded); /* Where is the item now */ if (tval_is_melee_weapon(wielded)) fmt = "You are wielding %s (%c)."; else if (wielded->tval == TV_BOW) fmt = "You are shooting with %s (%c)."; else if (tval_is_light(wielded)) fmt = "Your light source is %s (%c)."; else fmt = "You are wearing %s (%c)."; /* Describe the result */ object_desc(o_name, sizeof(o_name), wielded, ODESC_PREFIX | ODESC_FULL); /* Message */ msgt(MSG_WIELD, fmt, o_name, I2A(slot)); /* Cursed! */ if (wielded->curses) { /* Warn the player */ msgt(MSG_CURSED, "Oops! It feels deathly cold!"); } /* See if we have to overflow the pack */ combine_pack(); pack_overflow(old); /* Recalculate bonuses, torch, mana, gear */ player->upkeep->notice |= (PN_IGNORE); player->upkeep->update |= (PU_BONUS | PU_INVEN); player->upkeep->redraw |= (PR_INVEN | PR_EQUIP | PR_ARMOR); player->upkeep->redraw |= (PR_STATS | PR_HP | PR_MANA | PR_SPEED); /* Disable repeats */ cmd_disable_repeat(); }
/** * This is a helper function used by do_cmd_throw and do_cmd_fire. * * It abstracts out the projectile path, display code, identify and clean up * logic, while using the 'attack' parameter to do work particular to each * kind of attack. */ static void ranged_helper(struct object *obj, int dir, int range, int shots, ranged_attack attack) { int i, j; char o_name[80]; int path_n; struct loc path_g[256]; /* Start at the player */ int x = player->px; int y = player->py; /* Predict the "target" location */ int ty = y + 99 * ddy[dir]; int tx = x + 99 * ddx[dir]; bool hit_target = FALSE; bool none_left = FALSE; struct object *missile; /* Check for target validity */ if ((dir == 5) && target_okay()) { int taim; target_get(&tx, &ty); taim = distance(y, x, ty, tx); if (taim > range) { char msg[80]; strnfmt(msg, sizeof(msg), "Target out of range by %d squares. Fire anyway? ", taim - range); if (!get_check(msg)) return; } } /* Sound */ sound(MSG_SHOOT); /* Describe the object */ object_desc(o_name, sizeof(o_name), obj, ODESC_FULL | ODESC_SINGULAR); /* Actually "fire" the object -- Take a partial turn */ player->upkeep->energy_use = (z_info->move_energy / shots); /* Calculate the path */ path_n = project_path(path_g, range, y, x, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(player); /* Start at the player */ x = player->px; y = player->py; /* Project along the path */ for (i = 0; i < path_n; ++i) { struct monster *mon = NULL; int ny = path_g[i].y; int nx = path_g[i].x; bool see = square_isseen(cave, ny, nx); /* Stop before hitting walls */ if (!(square_ispassable(cave, ny, nx)) && !(square_isprojectable(cave, ny, nx))) break; /* Advance */ x = nx; y = ny; /* Tell the UI to display the missile */ event_signal_missile(EVENT_MISSILE, obj, see, y, x); /* Try the attack on the monster at (x, y) if any */ mon = square_monster(cave, y, x); if (mon) { int visible = mflag_has(mon->mflag, MFLAG_VISIBLE); bool fear = FALSE; const char *note_dies = monster_is_unusual(mon->race) ? " is destroyed." : " dies."; struct attack_result result = attack(obj, y, x); int dmg = result.dmg; u32b msg_type = result.msg_type; char hit_verb[20]; my_strcpy(hit_verb, result.hit_verb, sizeof(hit_verb)); mem_free(result.hit_verb); if (result.success) { hit_target = TRUE; object_notice_attack_plusses(obj); /* Learn by use for other equipped items */ equip_notice_to_hit_on_attack(player); /* No negative damage; change verb if no damage done */ if (dmg <= 0) { dmg = 0; msg_type = MSG_MISS; my_strcpy(hit_verb, "fails to harm", sizeof(hit_verb)); } if (!visible) { /* Invisible monster */ msgt(MSG_SHOOT_HIT, "The %s finds a mark.", o_name); } else { for (j = 0; j < (int)N_ELEMENTS(ranged_hit_types); j++) { char m_name[80]; const char *dmg_text = ""; if (msg_type != ranged_hit_types[j].msg) continue; if (OPT(show_damage)) dmg_text = format(" (%d)", dmg); monster_desc(m_name, sizeof(m_name), mon, MDESC_OBJE); if (ranged_hit_types[j].text) msgt(msg_type, "Your %s %s %s%s. %s", o_name, hit_verb, m_name, dmg_text, ranged_hit_types[j].text); else msgt(msg_type, "Your %s %s %s%s.", o_name, hit_verb, m_name, dmg_text); } /* Track this monster */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { monster_race_track(player->upkeep, mon->race); health_track(player->upkeep, mon); } } /* Hit the monster, check for death */ if (!mon_take_hit(mon, dmg, &fear, note_dies)) { message_pain(mon, dmg); if (fear && mflag_has(mon->mflag, MFLAG_VISIBLE)) { char m_name[80]; monster_desc(m_name, sizeof(m_name), mon, MDESC_DEFAULT); add_monster_message(m_name, mon, MON_MSG_FLEE_IN_TERROR, TRUE); } } } /* Stop the missile */ break; } /* Stop if non-projectable but passable */ if (!(square_isprojectable(cave, ny, nx))) break; } /* Get the missile */ if (object_is_carried(player, obj)) missile = gear_object_for_use(obj, 1, TRUE, &none_left); else missile = floor_object_for_use(obj, 1, TRUE, &none_left); /* Drop (or break) near that location */ drop_near(cave, missile, breakage_chance(missile, hit_target), y, x, TRUE); }