/** * Melee effect handler: Eat the player's food. */ static void melee_effect_handler_EAT_FOOD(melee_effect_handler_context_t *context) { /* Steal some food */ int tries; /* Take damage */ take_hit(context->p, context->damage, context->ddesc); for (tries = 0; tries < 10; tries++) { /* Pick an item from the pack */ int index = randint0(z_info->pack_size); struct object *obj, *eaten; char o_name[80]; /* Get the item */ obj = context->p->upkeep->inven[index]; /* Skip non-objects */ if (obj == NULL) continue; /* Skip non-food objects */ if (!tval_is_food(obj)) continue; if (obj->number == 1) { object_desc(o_name, sizeof(o_name), obj, ODESC_BASE); msg("Your %s (%c) was eaten!", o_name, I2A(index)); } else { object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_BASE); msg("One of your %s (%c) was eaten!", o_name, I2A(index)); } /* Steal and eat */ eaten = gear_object_for_use(obj, 1, FALSE); object_delete(eaten); /* Obvious */ context->obvious = TRUE; /* Done */ break; } }
/** * Gives the known effects of using the given item. * * Fills in: * - the effect id, or OBJ_KNOWN_PRESENT if there is an effect but details * are unknown * - whether the effect can be aimed * - the minimum and maximum time in game turns for the item to recharge * (or zero if it does not recharge) * - the percentage chance of the effect failing when used * * Return FALSE if the object has no effect. */ static bool obj_known_effect(const struct object *obj, int *effect, bool *aimed, int *min_recharge, int *max_recharge, int *failure_chance) { random_value timeout = {0, 0, 0, 0}; *effect = 0; *min_recharge = 0; *max_recharge = 0; *failure_chance = 0; *aimed = FALSE; if (object_effect_is_known(obj)) { *effect = object_effect(obj); timeout = obj->time; } else if (object_effect(obj)) { /* Don't know much - be vague */ *effect = OBJ_KNOWN_PRESENT; if (!obj->artifact && effect_aim(obj->effect)) *aimed = TRUE; return TRUE; } else { /* No effect - no info */ return FALSE; } if (randcalc(timeout, 0, MAXIMISE) > 0) { *min_recharge = randcalc(timeout, 0, MINIMISE); *max_recharge = randcalc(timeout, 0, MAXIMISE); } if (tval_is_food(obj) || tval_is_potion(obj) || tval_is_scroll(obj)) { *failure_chance = 0; } else { *failure_chance = get_use_device_chance(obj); } return TRUE; }
/** * Wipe an object clean and make it a standard object of the specified kind. */ void object_prep(struct object *o_ptr, struct object_kind *k, int lev, aspect rand_aspect) { int i; /* Clean slate */ memset(o_ptr, 0, sizeof(*o_ptr)); /* Assign the kind and copy across data */ o_ptr->kind = k; o_ptr->tval = k->tval; o_ptr->sval = k->sval; o_ptr->ac = k->ac; o_ptr->dd = k->dd; o_ptr->ds = k->ds; o_ptr->weight = k->weight; o_ptr->effect = k->effect; o_ptr->time = k->time; /* Weight is always known */ id_on(o_ptr->id_flags, ID_WEIGHT); /* Default number */ o_ptr->number = 1; /* Copy flags */ of_copy(o_ptr->flags, k->base->flags); of_copy(o_ptr->flags, k->flags); /* Assign modifiers */ for (i = 0; i < OBJ_MOD_MAX; i++) o_ptr->modifiers[i] = randcalc(k->modifiers[i], lev, rand_aspect); /* Assign charges (wands/staves only) */ if (tval_can_have_charges(o_ptr)) o_ptr->pval = randcalc(k->charge, lev, rand_aspect); /* Assign pval for food, oil and launchers */ if (tval_is_food(o_ptr) || tval_is_potion(o_ptr) || tval_is_fuel(o_ptr) || tval_is_launcher(o_ptr)) o_ptr->pval = randcalc(k->pval, lev, rand_aspect); /* Default fuel */ if (tval_is_light(o_ptr)) { if (of_has(o_ptr->flags, OF_BURNS_OUT)) o_ptr->timeout = z_info->fuel_torch; else if (of_has(o_ptr->flags, OF_TAKES_FUEL)) o_ptr->timeout = z_info->default_lamp; } /* Default magic */ o_ptr->to_h = randcalc(k->to_h, lev, rand_aspect); o_ptr->to_d = randcalc(k->to_d, lev, rand_aspect); o_ptr->to_a = randcalc(k->to_a, lev, rand_aspect); /* Default slays and brands */ copy_slay(&o_ptr->slays, k->slays); copy_brand(&o_ptr->brands, k->brands); /* Default resists */ for (i = 0; i < ELEM_MAX; i++) { o_ptr->el_info[i].res_level = k->el_info[i].res_level; o_ptr->el_info[i].flags = k->el_info[i].flags; o_ptr->el_info[i].flags |= k->base->el_info[i].flags; /* Unresistables have no hidden properties */ if (i > ELEM_HIGH_MAX) o_ptr->el_info[i].flags |= EL_INFO_KNOWN; } }
/** * Determine if an item can "absorb" a second item * * See "object_absorb()" for the actual "absorption" code. * * If permitted, we allow weapons/armor to stack, if "known". * * Missiles will combine if both stacks have the same "known" status. * This is done to make unidentified stacks of missiles useful. * * Food, potions, scrolls, and "easy know" items always stack. * * Chests, and activatable items, except rods, never stack (for various * reasons). */ bool object_stackable(const struct object *obj1, const struct object *obj2, object_stack_t mode) { int i; /* Equipment items don't stack */ if (object_is_equipped(player->body, obj1)) return FALSE; if (object_is_equipped(player->body, obj2)) return FALSE; /* If either item is unknown, do not stack */ if (mode & OSTACK_LIST && obj1->marked == MARK_AWARE) return FALSE; if (mode & OSTACK_LIST && obj2->marked == MARK_AWARE) return FALSE; /* Hack -- identical items cannot be stacked */ if (obj1 == obj2) return FALSE; /* Require identical object kinds */ if (obj1->kind != obj2->kind) return FALSE; /* Different flags don't stack */ if (!of_is_equal(obj1->flags, obj2->flags)) return FALSE; /* Different elements don't stack */ for (i = 0; i < ELEM_MAX; i++) { if (obj1->el_info[i].res_level != obj2->el_info[i].res_level) return FALSE; if ((obj1->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE)) != (obj2->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE))) return FALSE; } /* Artifacts never stack */ if (obj1->artifact || obj2->artifact) return FALSE; /* Analyze the items */ if (tval_is_chest(obj1)) { /* Chests never stack */ return FALSE; } else if (tval_is_food(obj1) || tval_is_potion(obj1) || tval_is_scroll(obj1) || tval_is_rod(obj1)) { /* Food, potions, scrolls and rods all stack nicely, since the kinds are identical, either both will be aware or both will be unaware */ } else if (tval_can_have_charges(obj1) || tval_is_money(obj1)) { /* Gold, staves and wands stack most of the time */ /* Too much gold or too many charges */ if (obj1->pval + obj2->pval > MAX_PVAL) return FALSE; /* ... otherwise ok */ } else if (tval_is_weapon(obj1) || tval_is_armor(obj1) || tval_is_jewelry(obj1) || tval_is_light(obj1)) { bool obj1_is_known = object_is_known(obj1); bool obj2_is_known = object_is_known(obj2); /* Require identical values */ if (obj1->ac != obj2->ac) return FALSE; if (obj1->dd != obj2->dd) return FALSE; if (obj1->ds != obj2->ds) return FALSE; /* Require identical bonuses */ if (obj1->to_h != obj2->to_h) return FALSE; if (obj1->to_d != obj2->to_d) return FALSE; if (obj1->to_a != obj2->to_a) return FALSE; /* Require all identical modifiers */ for (i = 0; i < OBJ_MOD_MAX; i++) if (obj1->modifiers[i] != obj2->modifiers[i]) return (FALSE); /* Require identical ego-item types */ if (obj1->ego != obj2->ego) return FALSE; /* Hack - Never stack recharging wearables ... */ if ((obj1->timeout || obj2->timeout) && !tval_is_light(obj1)) return FALSE; /* ... and lights must have same amount of fuel */ else if ((obj1->timeout != obj2->timeout) && tval_is_light(obj1)) return FALSE; /* Prevent unIDd items stacking with IDd items in the object list */ if (mode & OSTACK_LIST && (obj1_is_known != obj2_is_known)) return FALSE; } else { /* Anything else probably okay */ } /* Require compatible inscriptions */ if (obj1->note && obj2->note && (obj1->note != obj2->note)) return FALSE; /* They must be similar enough */ return TRUE; }