/** * Apply generation magic to an ego-item. */ void ego_apply_magic(struct object *obj, int level) { int i, x, resist = 0; bitflag newf[OF_SIZE]; /* Extra powers */ if (kf_has(obj->ego->kind_flags, KF_RAND_SUSTAIN)) { create_mask(newf, false, OFT_SUST, OFT_MAX); of_on(obj->flags, get_new_attr(obj->flags, newf)); } else if (kf_has(obj->ego->kind_flags, KF_RAND_POWER)) { create_mask(newf, false, OFT_PROT, OFT_MISC, OFT_MAX); of_on(obj->flags, get_new_attr(obj->flags, newf)); } else if (kf_has(obj->ego->kind_flags, KF_RAND_HI_RES)) /* Get a high resist if available, mark it as random */ if (random_high_resist(obj, &resist)) { obj->el_info[resist].res_level = 1; obj->el_info[resist].flags |= EL_INFO_RANDOM; } /* Apply extra obj->ego bonuses */ obj->to_h += randcalc(obj->ego->to_h, level, RANDOMISE); obj->to_d += randcalc(obj->ego->to_d, level, RANDOMISE); obj->to_a += randcalc(obj->ego->to_a, level, RANDOMISE); /* Apply modifiers */ for (i = 0; i < OBJ_MOD_MAX; i++) { x = randcalc(obj->ego->modifiers[i], level, RANDOMISE); obj->modifiers[i] += x; } /* Apply flags */ of_union(obj->flags, obj->ego->flags); of_diff(obj->flags, obj->ego->flags_off); /* Add slays and brands */ copy_slay(&obj->slays, obj->ego->slays); copy_brand(&obj->brands, obj->ego->brands); /* Add resists */ for (i = 0; i < ELEM_MAX; i++) { /* Take the larger of ego and base object resist levels */ obj->el_info[i].res_level = MAX(obj->ego->el_info[i].res_level, obj->el_info[i].res_level); /* Union of flags so as to know when ignoring is notable */ obj->el_info[i].flags |= obj->ego->el_info[i].flags; } /* Add effect (ego effect will trump object effect, when there are any) */ if (obj->ego->effect) { obj->effect = obj->ego->effect; obj->time = obj->ego->time; } return; }
/** * Prepare an object based on an object kind. */ void object_prep(object_type * o_ptr, int k_idx, aspect rand_aspect) { int i; object_kind *k_ptr = &k_info[k_idx]; /* Clear the record */ (void) WIPE(o_ptr, object_type); /* Save the kind */ o_ptr->k_idx = k_idx; o_ptr->kind = k_ptr; /* Efficiency -- tval/sval */ o_ptr->tval = k_ptr->tval; o_ptr->sval = k_ptr->sval; /* Default "pval" */ o_ptr->pval = randcalc(k_ptr->pval, k_ptr->level, rand_aspect); /* Default number */ o_ptr->number = 1; /* Default weight */ o_ptr->weight = k_ptr->weight; /* Default magic */ o_ptr->to_h = randcalc(k_ptr->to_h, k_ptr->level, rand_aspect); o_ptr->to_d = randcalc(k_ptr->to_d, k_ptr->level, rand_aspect); o_ptr->to_a = randcalc(k_ptr->to_a, k_ptr->level, rand_aspect); /* Default power */ o_ptr->ac = k_ptr->ac; o_ptr->dd = k_ptr->dd; o_ptr->ds = k_ptr->ds; /* Default effect and time */ o_ptr->effect = k_ptr->effect; o_ptr->time = k_ptr->time; /* Default flags */ of_copy(o_ptr->flags_obj, k_ptr->flags_obj); cf_copy(o_ptr->flags_curse, k_ptr->flags_curse); /* Default resists, bonuses, multiples */ for (i = 0; i < MAX_P_RES; i++) o_ptr->percent_res[i] = k_ptr->percent_res[i]; for (i = 0; i < A_MAX; i++) o_ptr->bonus_stat[i] = k_ptr->bonus_stat[i]; for (i = 0; i < MAX_P_BONUS; i++) o_ptr->bonus_other[i] = k_ptr->bonus_other[i]; for (i = 0; i < MAX_P_SLAY; i++) o_ptr->multiple_slay[i] = k_ptr->multiple_slay[i]; for (i = 0; i < MAX_P_BRAND; i++) o_ptr->multiple_brand[i] = k_ptr->multiple_brand[i]; }
/** * Test whether an object is intrinsically good. * * Note that this test only applies to the object *kind*, so it is * possible to choose a kind which is good, and then later cause * the actual object to be cursed. We do explicitly forbid objects * which are known to be boring or which start out somewhat damaged. */ static bool kind_is_good(const object_kind *kind) { if (of_has(kind->flags, OF_GOOD) || of_has(kind->base->flags, OF_GOOD)) return TRUE; if (randcalc(kind->to_a, 0, MINIMISE) < 0) return FALSE; if (randcalc(kind->to_d, 0, MINIMISE) < 0) return FALSE; if (kind_is_armour(kind->tval)) return TRUE; if (randcalc(kind->to_h, 0, MINIMISE) < 0) return FALSE; if (kind_is_weapon(kind->tval) || kind_is_ammo(kind->tval)) return TRUE; return FALSE; }
/** * Wipe an object clean and make it a standard object of the specified kind. */ void object_prep(object_type *o_ptr, struct object_kind *k, int lev, aspect rand_aspect) { int i, flag, pval; bitflag flags[OF_SIZE], f2[OF_SIZE]; /* Clean slate */ WIPE(o_ptr, object_type); /* 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; /* Default number */ o_ptr->number = 1; /* Apply pvals and then copy flags */ of_copy(f2, k->flags); for (i = 0; i < k->num_pvals; i++) { of_copy(flags, k->pval_flags[i]); pval = randcalc(k->pval[i], lev, rand_aspect); for (flag = of_next(flags, FLAG_START); flag != FLAG_END; flag = of_next(flags, flag + 1)) /* Prevent phantom flags */ if (pval) object_add_pval(o_ptr, pval, flag); else of_off(f2, flag); } of_copy(o_ptr->flags, k->base->flags); of_union(o_ptr->flags, f2); /* Assign charges/food/fuel value (wands/staves/food/oil) */ o_ptr->extent = randcalc(k->extent, lev, rand_aspect); /* Default fuel for lamps */ if (o_ptr->tval == TV_LIGHT) { if (o_ptr->sval == SV_LIGHT_TORCH) o_ptr->timeout = DEFAULT_TORCH; else if (o_ptr->sval == SV_LIGHT_LANTERN) o_ptr->timeout = 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); }
/** * Adjust damage according to resistance or vulnerability. * * \param p is the player * \param type is the attack type we are checking. * \param dam is the unadjusted damage. * \param dam_aspect is the calc we want (min, avg, max, random). * \param resist is the degree of resistance (-1 = vuln, 3 = immune). */ int adjust_dam(struct player *p, int type, int dam, aspect dam_aspect, int resist, bool actual) { int i, denom = 0; /* If an actual player exists, get their actual resist */ if (p && p->race) { /* Ice is a special case */ int res_type = (type == PROJ_ICE) ? PROJ_COLD: type; resist = p->state.el_info[res_type].res_level; /* Notice element stuff */ if (actual) { equip_learn_element(p, res_type); } } if (resist == 3) /* immune */ return 0; /* Hack - acid damage is halved by armour, holy orb is halved */ if ((type == PROJ_ACID && p && minus_ac(p)) || type == PROJ_HOLY_ORB) dam = (dam + 1) / 2; if (resist == -1) /* vulnerable */ return (dam * 4 / 3); /* Variable resists vary the denominator, so we need to invert the logic * of dam_aspect. (m_bonus is unused) */ switch (dam_aspect) { case MINIMISE: denom = randcalc(projections[type].denominator, 0, MAXIMISE); break; case MAXIMISE: denom = randcalc(projections[type].denominator, 0, MINIMISE); break; case AVERAGE: case EXTREMIFY: case RANDOMISE: denom = randcalc(projections[type].denominator, 0, dam_aspect); break; default: assert(0); } for (i = resist; i > 0; i--) if (denom) dam = dam * projections[type].numerator / denom; return dam; }
/** * Prepare an object `dst` representing `amt` objects, based on an existing * object `src` representing at least `amt` objects. * * Takes care of the charge redistribution concerns of stacked items. */ void object_copy_amt(struct object *dest, struct object *src, int amt) { int charge_time = randcalc(src->time, 0, AVERAGE), max_time; /* Get a copy of the object */ object_copy(dest, src); /* Modify quantity */ dest->number = amt; dest->note = src->note; /* * If the item has charges/timeouts, set them to the correct level * too. We split off the same amount as distribute_charges. */ if (tval_can_have_charges(src)) dest->pval = src->pval * amt / src->number; if (tval_can_have_timeout(src)) { max_time = charge_time * amt; if (src->timeout > max_time) dest->timeout = max_time; else dest->timeout = src->timeout; } }
/** * Critical blow. All hits that do 95% of total possible damage, * and which also do at least 20 damage, or, sometimes, N damage. * This is used only to determine "cuts" and "stuns". */ static int monster_critical(random_value dice, int rlev, int dam) { int max = 0; int total = randcalc(dice, rlev, MAXIMISE); /* Must do at least 95% of perfect */ if (dam < total * 19 / 20) return (0); /* Weak blows rarely work */ if ((dam < 20) && (randint0(100) >= dam)) return (0); /* Perfect damage */ if (dam == total) max++; /* Super-charge */ if (dam >= 20) while (randint0(100) < 2) max++; /* Critical damage */ if (dam > 45) return (6 + max); if (dam > 33) return (5 + max); if (dam > 25) return (4 + max); if (dam > 18) return (3 + max); if (dam > 11) return (2 + max); return (1 + max); }
/** * Make a new trap of the given type. Return true if successful. * * We choose a player trap at random if the index is not legal. This means that * things which are not player traps must be picked by passing a valid index. * * This should be the only function that places traps in the dungeon * except the savefile loading code. */ void place_trap(struct chunk *c, int y, int x, int t_idx, int trap_level) { struct trap *new_trap; /* We've been called with an illegal index; choose a random trap */ if ((t_idx <= 0) || (t_idx >= z_info->trap_max)) { /* Require the correct terrain */ if (!square_player_trap_allowed(c, y, x)) return; t_idx = pick_trap(c, c->squares[y][x].feat, trap_level); } /* Failure */ if (t_idx < 0) return; /* Allocate a new trap for this grid (at the front of the list) */ new_trap = mem_zalloc(sizeof(*new_trap)); new_trap->next = square_trap(c, y, x); c->squares[y][x].trap = new_trap; /* Set the details */ new_trap->t_idx = t_idx; new_trap->kind = &trap_info[t_idx]; new_trap->fy = y; new_trap->fx = x; new_trap->power = randcalc(new_trap->kind->power, trap_level, RANDOMISE); trf_copy(new_trap->flags, trap_info[t_idx].flags); /* Toggle on the trap marker */ sqinfo_on(c->squares[y][x].info, SQUARE_TRAP); /* Redraw the grid */ square_light_spot(c, y, x); }
/** * Hack -- determine if a template is "good". * * Note that this test only applies to the object *kind*, so it is * possible to choose a kind which is "good", and then later cause * the actual object to be cursed. We do explicitly forbid objects * which are known to be boring or which start out somewhat damaged. */ bool kind_is_good(const struct object_kind *kind) { /* Some item types are (almost) always good */ switch (kind->tval) { /* Armor -- Good unless damaged */ case TV_HARD_ARMOR: case TV_SOFT_ARMOR: case TV_DRAG_ARMOR: case TV_SHIELD: case TV_CLOAK: case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: { if (randcalc(kind->to_a, 0, MINIMISE) < 0) return (false); return true; } /* Weapons -- Good unless damaged */ case TV_BOW: case TV_SWORD: case TV_HAFTED: case TV_POLEARM: case TV_DIGGING: { if (randcalc(kind->to_h, 0, MINIMISE) < 0) return (false); if (randcalc(kind->to_d, 0, MINIMISE) < 0) return (false); return true; } /* Ammo -- Arrows/Bolts are good */ case TV_BOLT: case TV_ARROW: { return true; } } /* Anything with the GOOD flag */ if (kf_has(kind->kind_flags, KF_GOOD)) return true; /* Assume not good */ return (false); }
/** * Gives the known effects of using the given item. * * Fills in: * - the effect * - 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, struct effect **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; if (effect_aim(*effect)) *aimed = true;; } else if (object_effect(obj)) { /* Don't know much - be vague */ *effect = NULL; if (!obj->artifact && effect_aim(object_effect(obj))) *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_edible(obj) || tval_is_potion(obj) || tval_is_scroll(obj)) { *failure_chance = 0; } else { *failure_chance = get_use_device_chance(obj); } return true; }
/** * Attempt to make an object * * \param c is the current dungeon level. * \param j_ptr is the object struct to be populated. * \param lev is the creation level of the object (not necessarily == depth). * \param good is whether the object is to be good * \param great is whether the object is to be great * \param value is the value to be returned to the calling function * * Returns the whether or not creation worked. */ bool make_object(struct cave *c, object_type *j_ptr, int lev, bool good, bool great, s32b *value) { int base, art, div; object_kind *kind; /* Base level and artifact chance for the object */ if (great) { art = ART_GREAT; base = lev + 10 + m_bonus(5, lev); } else if (good) { art = ART_GOOD; base = lev + 5 + m_bonus(5, lev); } else { art = ART_NORMAL; base = lev; } /* Small hack to bring artifact frequencies at low depths in line with V */ div = 9 - p_ptr->depth; if (div < 1) div = 1; /* Try to make an artifact */ if (one_in_(art * div)) { if (make_artifact(j_ptr, lev)) { if (value) *value = object_value_real(j_ptr, 1, FALSE, TRUE); return TRUE; } } /* Get the object, prep it and apply magic */ kind = get_obj_num(base, good || great); if (!kind) return FALSE; object_prep(j_ptr, kind, base, RANDOMISE); apply_magic(j_ptr, base, FALSE, good, great); /* Generate multiple items */ if (kind->gen_mult_prob >= randint1(100)) j_ptr->number = randcalc(kind->stack_size, lev, RANDOMISE); if (j_ptr->number >= MAX_STACK_SIZE) j_ptr->number = MAX_STACK_SIZE - 1; /* Return value, increased for uncursed out-of-depth objects */ if (value) *value = object_value_real(j_ptr, j_ptr->number, FALSE, TRUE); if (!cursed_p(j_ptr->flags) && (kind->alloc_min > c->depth)) { if (value) *value = (kind->alloc_min - c->depth) * (*value / 5); } return TRUE; }
/** * Apply generation magic to an ego-item. */ void ego_apply_magic(object_type *o_ptr, int level) { int i, flag, x; bitflag flags[OF_SIZE], newf[OF_SIZE], f2[OF_SIZE]; object_flags(o_ptr, flags); /* Extra powers */ if (o_ptr->ego->xtra == OBJECT_XTRA_TYPE_SUSTAIN) create_mask(newf, FALSE, OFT_SUST, OFT_MAX); else if (o_ptr->ego->xtra == OBJECT_XTRA_TYPE_RESIST) create_mask(newf, FALSE, OFT_HRES, OFT_MAX); else if (o_ptr->ego->xtra == OBJECT_XTRA_TYPE_POWER) create_mask(newf, FALSE, OFT_PROT, OFT_MISC, OFT_MAX); if (o_ptr->ego->xtra) of_on(o_ptr->flags, get_new_attr(flags, newf)); /* Apply extra o_ptr->ego bonuses */ o_ptr->to_h += randcalc(o_ptr->ego->to_h, level, RANDOMISE); o_ptr->to_d += randcalc(o_ptr->ego->to_d, level, RANDOMISE); o_ptr->to_a += randcalc(o_ptr->ego->to_a, level, RANDOMISE); /* Apply pvals */ of_copy(f2, o_ptr->ego->flags); for (i = 0; i < o_ptr->ego->num_pvals; i++) { of_copy(flags, o_ptr->ego->pval_flags[i]); x = randcalc(o_ptr->ego->pval[i], level, RANDOMISE); for (flag = of_next(flags, FLAG_START); flag != FLAG_END; flag = of_next(flags, flag + 1)) /* Prevent phantom flags */ if (x) object_add_pval(o_ptr, x, flag); else of_off(f2, flag); } /* Apply remaining flags */ of_union(o_ptr->flags, f2); return; }
/** * Attempt to make an object * * \param c is the current dungeon level. * \param lev is the creation level of the object (not necessarily == depth). * \param good is whether the object is to be good * \param great is whether the object is to be great * \param extra_roll is whether we get an extra roll in apply_magic() * \param value is the value to be returned to the calling function * \param tval is the desired tval, or 0 if we allow any tval * * \return a pointer to the newly allocated object, or NULL on failure. */ struct object *make_object(struct chunk *c, int lev, bool good, bool great, bool extra_roll, s32b *value, int tval) { int base; struct object_kind *kind; struct object *new_obj; /* Try to make a special artifact */ if (one_in_(good ? 10 : 1000)) { new_obj = make_artifact_special(lev); if (new_obj) { if (value) *value = object_value_real(new_obj, 1, false); return new_obj; } /* If we failed to make an artifact, the player gets a good item */ good = true; } /* Base level for the object */ base = (good ? (lev + 10) : lev); /* Try to choose an object kind */ kind = get_obj_num(base, good || great, tval); if (!kind) return NULL; /* Make the object, prep it and apply magic */ new_obj = object_new(); object_prep(new_obj, kind, lev, RANDOMISE); if (one_in_(20) && tval_is_wearable(new_obj)) { apply_curse(new_obj, &lev); } apply_magic(new_obj, lev, true, good, great, extra_roll); apply_curse_knowledge(new_obj); /* Generate multiple items */ if (kind->gen_mult_prob >= randint1(100)) new_obj->number = randcalc(kind->stack_size, lev, RANDOMISE); if (new_obj->number > z_info->stack_size) new_obj->number = z_info->stack_size; /* Get the value */ if (value) *value = object_value_real(new_obj, new_obj->number, false); /* Boost of 20% per level OOD for uncursed objects */ if ((!new_obj->curses) && (kind->alloc_min > c->depth)) { if (value) *value += (kind->alloc_min - c->depth) * (*value / 5); } return new_obj; }
/* * Prepare an object based on an object kind. * Use the specified randomization aspect */ void object_prep(object_type *o_ptr, int k_idx, int lev, aspect rand_aspect) { object_kind *k_ptr = &k_info[k_idx]; /* Clear the record */ (void)WIPE(o_ptr, object_type); /* Save the kind index */ o_ptr->k_idx = k_idx; /* Efficiency -- tval/sval */ o_ptr->tval = k_ptr->tval; o_ptr->sval = k_ptr->sval; /* Default number */ o_ptr->number = 1; /* Default "pval" */ o_ptr->pval = randcalc(k_ptr->pval, lev, rand_aspect); /* Default weight */ o_ptr->weight = k_ptr->weight; /* Assign charges (wands/staves only) */ if (o_ptr->tval == TV_WAND || o_ptr->tval == TV_STAFF) o_ptr->pval = randcalc(k_ptr->charge, lev, rand_aspect); /* Default magic */ o_ptr->to_h = randcalc(k_ptr->to_h, lev, rand_aspect); o_ptr->to_d = randcalc(k_ptr->to_d, lev, rand_aspect); o_ptr->to_a = randcalc(k_ptr->to_a, lev, rand_aspect); /* Default power */ o_ptr->ac = k_ptr->ac; o_ptr->dd = k_ptr->dd; o_ptr->ds = k_ptr->ds; /* Hack -- cursed items are always "cursed" */ if (of_has(k_ptr->flags, OF_LIGHT_CURSE)) of_on(o_ptr->flags, OF_LIGHT_CURSE); }
/** * 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; }
/** * Attempt to make an object * * \param c is the current dungeon level. * \param lev is the creation level of the object (not necessarily == depth). * \param good is whether the object is to be good * \param great is whether the object is to be great * \param extra_roll is whether we get an extra roll in apply_magic() * \param value is the value to be returned to the calling function * \param tval is the desired tval, or 0 if we allow any tval * * \return a pointer to the newly allocated object, or NULL on failure. */ struct object *make_object(struct chunk *c, int lev, bool good, bool great, bool extra_roll, s32b *value, int tval) { int base; object_kind *kind; struct object *new_obj; /* Try to make a special artifact */ if (one_in_(good ? 10 : 1000)) { new_obj = make_artifact_special(lev); if (new_obj) { if (value) *value = object_value_real(new_obj, 1, FALSE, TRUE); return new_obj; } /* If we failed to make an artifact, the player gets a good item */ good = TRUE; } /* Base level for the object */ base = (good ? (lev + 10) : lev); /* Try to choose an object kind */ kind = get_obj_num(base, good || great, tval); if (!kind) return NULL; /* Make the object, prep it and apply magic */ new_obj = object_new(); object_prep(new_obj, kind, lev, RANDOMISE); apply_magic(new_obj, lev, TRUE, good, great, extra_roll); /* Generate multiple items */ if (kind->gen_mult_prob >= randint1(100)) new_obj->number = randcalc(kind->stack_size, lev, RANDOMISE); if (new_obj->number > z_info->stack_size) new_obj->number = z_info->stack_size; /* Return value, increased for uncursed out-of-depth objects */ if (value) *value = object_value_real(new_obj, new_obj->number, FALSE, TRUE); /* This seems to imply objects get less value from being > 1 but < 5 * levels out of depth - should it be *value +=... - NRM */ if (!cursed_p(new_obj->flags) && (kind->alloc_min > c->depth)) { if (value) *value = (kind->alloc_min - c->depth) * (*value / 5); } return new_obj; }
/* * Attempt to make an object (normal or good/great) * * This routine plays nasty games to generate the "special artifacts". * * We assume that the given object has been "wiped". */ bool make_object(object_type *j_ptr, int lev, bool good, bool great) { int k_idx, base; object_kind *k_ptr; /* Try to make a special artifact */ if (one_in_(good ? 10 : 1000)) { if (make_artifact_special(j_ptr, lev)) return TRUE; /* If we failed to make an artifact, the player gets a great item */ good = great = TRUE; } /* Base level for the object */ base = (good ? (lev + 10) : lev); /* Get the object */ k_idx = get_obj_num(base, good || great); if (!k_idx) return FALSE; /* Prepare the object */ object_prep(j_ptr, &k_info[k_idx], lev, RANDOMISE); /* Apply magic (allow artifacts) */ apply_magic(j_ptr, lev, TRUE, good, great); /* Generate multiple items */ k_ptr = &k_info[j_ptr->k_idx]; if (k_ptr->gen_mult_prob >= 100 || k_ptr->gen_mult_prob >= randint1(100)) { j_ptr->number = randcalc(k_ptr->stack_size, lev, RANDOMISE); } /* Notice "okay" out-of-depth objects */ if (!cursed_p(j_ptr) && (k_info[j_ptr->k_idx].level > p_ptr->depth)) { /* Rating increase */ rating += (k_info[j_ptr->k_idx].alloc_min - p_ptr->depth); /* Cheat -- peek at items */ if (OPT(cheat_peek)) object_mention(j_ptr); } return TRUE; }
static long eval_blow_effect(int effect, random_value atk_dam, int rlev) { int adjustment = monster_blow_effect_eval(effect); int power = randcalc(atk_dam, rlev, MAXIMISE); if (effect == RBE_POISON) { power *= 5; power /= 4; power += rlev; } else { power += adjustment; } return power; }
/** * Wipe an object clean and make it a standard object of the specified kind. */ void object_prep(object_type *o_ptr, struct object_kind *k, int lev, aspect rand_aspect) { int i, flag, x; bitflag flags[OF_SIZE]; /* Clean slate */ WIPE(o_ptr, object_type); /* 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; /* Default number */ o_ptr->number = 1; /* Apply pvals and then copy flags */ for (i = 0; i < k->num_pvals; i++) { of_copy(flags, k->pval_flags[i]); x = randcalc(k->pval[i], lev, rand_aspect); for (flag = of_next(flags, FLAG_START); flag != FLAG_END; flag = of_next(flags, flag + 1)) object_add_pval(o_ptr, x, flag); } of_copy(o_ptr->flags, k->base->flags); of_union(o_ptr->flags, k->flags); /* Assign charges (wands/staves only) */ if (o_ptr->tval == TV_WAND || o_ptr->tval == TV_STAFF) o_ptr->pval[DEFAULT_PVAL] = randcalc(k->charge, lev, rand_aspect); /* Assign flagless pval for food or oil */ if (o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION || o_ptr->tval == TV_FLASK) o_ptr->pval[DEFAULT_PVAL] = randcalc(k->pval[DEFAULT_PVAL], lev, rand_aspect); /* Default fuel for lamps */ if (o_ptr->tval == TV_LIGHT) { if (o_ptr->sval == SV_LIGHT_TORCH) o_ptr->timeout = DEFAULT_TORCH; else if (o_ptr->sval == SV_LIGHT_LANTERN) o_ptr->timeout = 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); }
static size_t obj_desc_charges(const object_type * o_ptr, char *buf, size_t max, size_t end) { object_kind *k_ptr = &k_info[o_ptr->k_idx]; bool aware = object_aware_p(o_ptr); /* Wands and Staffs have charges */ if (aware && (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND)) strnfcat(buf, max, &end, " (%d charge%s)", o_ptr->pval, PLURAL(o_ptr->pval)); /* Charging things */ else if (o_ptr->timeout > 0) { if (o_ptr->tval == TV_ROD && o_ptr->number > 1) { int power; int time_base = randcalc(k_ptr->time, 0, MINIMISE); if (!time_base) time_base = 1; /* * Find out how many rods are charging, by dividing * current timeout by each rod's maximum timeout. * Ensure that any remainder is rounded up. Display * very discharged stacks as merely fully discharged. */ power = (o_ptr->timeout + (time_base - 1)) / time_base; if (power > o_ptr->number) power = o_ptr->number; /* Display prettily */ strnfcat(buf, max, &end, " (%d charging)", power); } /* Artifacts, single rods */ else if (!(o_ptr->tval == TV_LIGHT && !artifact_p(o_ptr))) { strnfcat(buf, max, &end, " (charging)"); } } return end; }
/** * Attempt to make an object * * \param c is the current dungeon level. * \param j_ptr is the object struct to be populated. * \param lev is the creation level of the object (not necessarily == depth). * \param good is whether the object is to be good * \param great is whether the object is to be great * \param value is the value to be returned to the calling function * \param tval is the desired tval, or 0 if we allow any tval * * Returns the whether or not creation worked. */ bool make_object(struct cave *c, object_type *j_ptr, int lev, bool good, bool great, bool extra_roll, s32b *value, int tval) { int base; object_kind *kind; /* Try to make a special artifact */ if (one_in_(good ? 10 : 1000)) { if (make_artifact_special(j_ptr, lev)) { if (value) *value = object_value_real(j_ptr, 1, FALSE, TRUE); return TRUE; } /* If we failed to make an artifact, the player gets a good item */ good = TRUE; } /* Base level for the object */ base = (good ? (lev + 10) : lev); /* Get the object, prep it and apply magic */ kind = get_obj_num(base, good || great, tval); if (!kind) return FALSE; object_prep(j_ptr, kind, lev, RANDOMISE); apply_magic(j_ptr, lev, TRUE, good, great, extra_roll); /* Generate multiple items */ if (kind->gen_mult_prob >= randint1(100)) j_ptr->number = randcalc(kind->stack_size, lev, RANDOMISE); if (j_ptr->number >= MAX_STACK_SIZE) j_ptr->number = MAX_STACK_SIZE - 1; /* Return value, increased for uncursed out-of-depth objects */ if (value) *value = object_value_real(j_ptr, j_ptr->number, FALSE, TRUE); if (!cursed_p(j_ptr->flags) && (kind->alloc_min > c->depth)) { if (value) *value = (kind->alloc_min - c->depth) * (*value / 5); } return TRUE; }
/** * Determine the damage of a spell attack which ignores monster hp * (i.e. bolts and balls, including arrows/boulders/storms/etc.) * * \param spell is the attack type * \param rlev is the monster level of the attacker * \param aspect is the damage calc required (min, avg, max, random) */ static int nonhp_dam(int spell, int rlev, aspect dam_aspect) { const struct mon_spell *rs_ptr = &mon_spell_table[spell]; int dam; /* base damage is X + YdZ (m_bonus is not used) */ dam = randcalc(rs_ptr->base_dam, 0, dam_aspect); /* rlev-dependent damage (m_bonus is used as a switch) */ dam += (rlev * rs_ptr->rlev_dam.base / 100); if (rs_ptr->rlev_dam.m_bonus == 1) /* then rlev affects dice */ dam += damcalc(MIN(1, rs_ptr->rlev_dam.dice * rlev / 100), rs_ptr->rlev_dam.sides, dam_aspect); else /* rlev affects sides */ dam += damcalc(rs_ptr->rlev_dam.dice, rs_ptr->rlev_dam.sides * rlev / 100, dam_aspect); return dam; }
/** * Determine the damage of a spell attack which ignores monster hp * (i.e. bolts and balls, including arrows/boulders/storms/etc.) * * \param spell is the attack type * \param race is the monster race of the attacker * \param dam_aspect is the damage calc required (min, avg, max, random) */ static int nonhp_dam(const struct monster_spell *spell, const struct monster_race *race, aspect dam_aspect) { int dam = 0; struct effect *effect = spell->effect; /* Set the reference race for calculations */ ref_race = race; /* Now add the damage for each effect */ while (effect) { random_value rand; if (effect->dice) { dice_roll(effect->dice, &rand); dam += randcalc(rand, 0, dam_aspect); } effect = effect->next; } ref_race = NULL; return dam; }
/* * Read an object * * This function attempts to "repair" old savefiles, and to extract * the most up to date values for various object fields. */ static int rd_item(object_type *o_ptr) { byte old_dd; byte old_ds; byte tmp8u; size_t i; object_kind *k_ptr; char buf[128]; /* Kind */ rd_s16b(&o_ptr->k_idx); /* Paranoia */ if ((o_ptr->k_idx < 0) || (o_ptr->k_idx >= z_info->k_max)) return (-1); /* Location */ rd_byte(&o_ptr->iy); rd_byte(&o_ptr->ix); /* Type/Subtype */ rd_byte(&o_ptr->tval); rd_byte(&o_ptr->sval); rd_s16b(&o_ptr->pval); /* Pseudo-ID bit */ rd_byte(&tmp8u); rd_byte(&o_ptr->number); rd_s16b(&o_ptr->weight); rd_byte(&o_ptr->name1); rd_byte(&o_ptr->name2); rd_s16b(&o_ptr->timeout); rd_s16b(&o_ptr->to_h); rd_s16b(&o_ptr->to_d); rd_s16b(&o_ptr->to_a); rd_s16b(&o_ptr->ac); rd_byte(&old_dd); rd_byte(&old_ds); rd_byte(&tmp8u); rd_byte(&o_ptr->marked); rd_byte(&o_ptr->origin); rd_byte(&o_ptr->origin_depth); rd_u16b(&o_ptr->origin_xtra); /* Hack - XXX - MarbleDice - Maximum saveable flags = 96 */ for (i = 0; i < 12 && i < OF_SIZE; i++) rd_byte(&o_ptr->flags[i]); if (i < 12) strip_bytes(OF_SIZE - i); /* Monster holding object */ rd_s16b(&o_ptr->held_m_idx); rd_string(buf, sizeof(buf)); /* Save the inscription */ if (buf[0]) o_ptr->note = quark_add(buf); /* Lookup item kind */ o_ptr->k_idx = lookup_kind(o_ptr->tval, o_ptr->sval); k_ptr = &k_info[o_ptr->k_idx]; /* Return now in case of "blank" or "empty" objects */ if (!k_ptr->name || !o_ptr->k_idx) { o_ptr->k_idx = 0; return 0; } /* Repair non "wearable" items */ if (!wearable_p(o_ptr)) { /* Get the correct fields */ if (!randcalc_valid(k_ptr->to_h, o_ptr->to_h)) o_ptr->to_h = randcalc(k_ptr->to_h, o_ptr->origin_depth, RANDOMISE); if (!randcalc_valid(k_ptr->to_d, o_ptr->to_d)) o_ptr->to_d = randcalc(k_ptr->to_d, o_ptr->origin_depth, RANDOMISE); if (!randcalc_valid(k_ptr->to_a, o_ptr->to_a)) o_ptr->to_a = randcalc(k_ptr->to_a, o_ptr->origin_depth, RANDOMISE); /* Get the correct fields */ o_ptr->ac = k_ptr->ac; o_ptr->dd = k_ptr->dd; o_ptr->ds = k_ptr->ds; /* Get the correct weight */ o_ptr->weight = k_ptr->weight; /* Paranoia */ o_ptr->name1 = o_ptr->name2 = 0; /* All done */ return (0); } /* Paranoia */ if (o_ptr->name1) { artifact_type *a_ptr; /* Paranoia */ if (o_ptr->name1 >= z_info->a_max) return (-1); /* Obtain the artifact info */ a_ptr = &a_info[o_ptr->name1]; /* Verify that artifact */ if (!a_ptr->name) o_ptr->name1 = 0; } /* Paranoia */ if (o_ptr->name2) { ego_item_type *e_ptr; /* Paranoia */ if (o_ptr->name2 >= z_info->e_max) return (-1); /* Obtain the ego-item info */ e_ptr = &e_info[o_ptr->name2]; /* Verify that ego-item */ if (!e_ptr->name) o_ptr->name2 = 0; } /* Get the standard fields */ o_ptr->ac = k_ptr->ac; o_ptr->dd = k_ptr->dd; o_ptr->ds = k_ptr->ds; /* Get the standard weight */ o_ptr->weight = k_ptr->weight; /* Artifacts */ if (o_ptr->name1) { artifact_type *a_ptr; /* Obtain the artifact info */ a_ptr = &a_info[o_ptr->name1]; /* Get the new artifact "pval" */ o_ptr->pval = a_ptr->pval; /* Get the new artifact fields */ o_ptr->ac = a_ptr->ac; o_ptr->dd = a_ptr->dd; o_ptr->ds = a_ptr->ds; /* Get the new artifact weight */ o_ptr->weight = a_ptr->weight; } /* Ego items */ if (o_ptr->name2) { ego_item_type *e_ptr; /* Obtain the ego-item info */ e_ptr = &e_info[o_ptr->name2]; /* Hack -- keep some old fields */ if ((o_ptr->dd < old_dd) && (o_ptr->ds == old_ds)) { /* Keep old boosted damage dice */ o_ptr->dd = old_dd; } /* Hack -- enforce legal pval */ if (flags_test(e_ptr->flags, OF_SIZE, OF_PVAL_MASK, FLAG_END)) { /* Force a meaningful pval */ if (!o_ptr->pval) o_ptr->pval = 1; } } /* Success */ return (0); }
/* * Describe an object's effect, if any. */ static bool describe_effect(textblock *tb, const object_type *o_ptr, bool full, bool only_artifacts, bool subjective) { const char *desc; random_value timeout = {0, 0, 0, 0}; int effect = 0, fail; if (o_ptr->artifact) { if (object_effect_is_known(o_ptr) || full) { effect = o_ptr->artifact->effect; timeout = o_ptr->artifact->time; } else if (object_effect(o_ptr)) { textblock_append(tb, "It can be activated.\n"); return TRUE; } } else { /* Sometimes only print artifact activation info */ if (only_artifacts == TRUE) return FALSE; if (object_effect_is_known(o_ptr) || full) { effect = o_ptr->kind->effect; timeout = o_ptr->kind->time; } else if (object_effect(o_ptr) != 0) { if (effect_aim(o_ptr->kind->effect)) textblock_append(tb, "It can be aimed.\n"); else if (o_ptr->tval == TV_FOOD) textblock_append(tb, "It can be eaten.\n"); else if (o_ptr->tval == TV_POTION) textblock_append(tb, "It can be drunk.\n"); else if (o_ptr->tval == TV_SCROLL) textblock_append(tb, "It can be read.\n"); else textblock_append(tb, "It can be activated.\n"); return TRUE; } } /* Forget it without an effect */ if (!effect) return FALSE; /* Obtain the description */ desc = effect_desc(effect); if (!desc) return FALSE; if (effect_aim(effect)) textblock_append(tb, "When aimed, it "); else if (o_ptr->tval == TV_FOOD) textblock_append(tb, "When eaten, it "); else if (o_ptr->tval == TV_POTION) textblock_append(tb, "When drunk, it "); else if (o_ptr->tval == TV_SCROLL) textblock_append(tb, "When read, it "); else textblock_append(tb, "When activated, it "); /* Print a colourised description */ do { if (isdigit((unsigned char) *desc)) textblock_append_c(tb, TERM_L_GREEN, "%c", *desc); else textblock_append(tb, "%c", *desc); } while (*desc++); textblock_append(tb, ".\n"); if (randcalc(timeout, 0, MAXIMISE) > 0) { int min_time, max_time; /* Sometimes adjust for player speed */ int multiplier = extract_energy[p_ptr->state.speed]; if (!subjective) multiplier = 10; textblock_append(tb, "Takes "); /* Correct for player speed */ min_time = randcalc(timeout, 0, MINIMISE) * multiplier / 10; max_time = randcalc(timeout, 0, MAXIMISE) * multiplier / 10; textblock_append_c(tb, TERM_L_GREEN, "%d", min_time); if (min_time != max_time) { textblock_append(tb, " to "); textblock_append_c(tb, TERM_L_GREEN, "%d", max_time); } textblock_append(tb, " turns to recharge"); if (subjective && p_ptr->state.speed != 110) textblock_append(tb, " at your current speed"); textblock_append(tb, ".\n"); } if (!subjective || o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION || o_ptr->tval == TV_SCROLL) { return TRUE; } else { fail = get_use_device_chance(o_ptr); textblock_append(tb, "Your chance of success is %d.%d%%\n", (1000 - fail) / 10, (1000 - fail) % 10); } return TRUE; }
/** * Small helper function to see how an object trait compares to the one * in its base type. * * If the base type provides a positive bonus, we'll use that. Otherwise, we'll * use zero (players don't consider an item with a positive bonus to be bad * even if the base kind has a higher positive bonus). */ static int cmp_object_trait(int bonus, random_value base) { int amt = randcalc(base, 0, MINIMISE); if (amt > 0) amt = 0; return CMP(bonus, amt); }
/* * 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); } }
/** * Wipe an object clean and make it a standard object of the specified kind. */ void object_prep(struct object *obj, struct object_kind *k, int lev, aspect rand_aspect) { int i; /* Clean slate */ memset(obj, 0, sizeof(*obj)); /* Assign the kind and copy across data */ obj->kind = k; obj->tval = k->tval; obj->sval = k->sval; obj->ac = k->ac; obj->dd = k->dd; obj->ds = k->ds; obj->weight = k->weight; obj->effect = k->effect; obj->time = k->time; /* Default number */ obj->number = 1; /* Copy flags */ of_copy(obj->flags, k->base->flags); of_copy(obj->flags, k->flags); /* Assign modifiers */ for (i = 0; i < OBJ_MOD_MAX; i++) obj->modifiers[i] = randcalc(k->modifiers[i], lev, rand_aspect); /* Assign charges (wands/staves only) */ if (tval_can_have_charges(obj)) obj->pval = randcalc(k->charge, lev, rand_aspect); /* Assign pval for food, oil and launchers */ if (tval_is_edible(obj) || tval_is_potion(obj) || tval_is_fuel(obj) || tval_is_launcher(obj)) obj->pval = randcalc(k->pval, lev, rand_aspect); /* Default fuel */ if (tval_is_light(obj)) { if (of_has(obj->flags, OF_BURNS_OUT)) obj->timeout = z_info->fuel_torch; else if (of_has(obj->flags, OF_TAKES_FUEL)) obj->timeout = z_info->default_lamp; } /* Default magic */ obj->to_h = randcalc(k->to_h, lev, rand_aspect); obj->to_d = randcalc(k->to_d, lev, rand_aspect); obj->to_a = randcalc(k->to_a, lev, rand_aspect); /* Default slays and brands */ copy_slay(&obj->slays, k->slays); copy_brand(&obj->brands, k->brands); /* Default resists */ for (i = 0; i < ELEM_MAX; i++) { obj->el_info[i].res_level = k->el_info[i].res_level; obj->el_info[i].flags = k->el_info[i].flags; obj->el_info[i].flags |= k->base->el_info[i].flags; } }
/** * Apply magic to miscellanious items * * Hack -- note the special code for various items */ static void a_m_aux_4(object_type * o_ptr, int level, int power) { object_kind *k_ptr = &k_info[o_ptr->k_idx]; /* Apply magic (good or bad) according to type */ switch (o_ptr->tval) { case TV_LIGHT: { /* Hack -- Torches -- random fuel */ if (o_ptr->sval == SV_LIGHT_TORCH) { if (o_ptr->pval > 0) o_ptr->pval = randint1(o_ptr->pval); } /* Hack -- Lanterns -- random fuel */ if (o_ptr->sval == SV_LIGHT_LANTERN) { if (o_ptr->pval > 0) o_ptr->pval = randint1(o_ptr->pval); } break; } case TV_WAND: case TV_STAFF: { int temp_pval = randcalc(k_ptr->pval, level, RANDOMISE); /* The wand or staff gets a number of initial charges equal to * between 1/2 (+1) and the full object kind's pval. */ o_ptr->pval = temp_pval / 2 + randint1((temp_pval + 1) / 2); break; } case TV_ROD: { /* Transfer the pval. */ o_ptr->pval = randcalc(k_ptr->pval, level, RANDOMISE); break; } case TV_CHEST: /* changed by LM */ { /* Hack -- pick a "value/difficulty", capable of being as little as * chest level - 16... */ o_ptr->pval = (k_info[o_ptr->k_idx].level) + 20 - damroll(4, 9); /* ...and never exceeding chest level + 4. */ if (o_ptr->pval > k_info[o_ptr->k_idx].level) o_ptr->pval = k_info[o_ptr->k_idx].level + randint1(4); /* Value/difficulty cannot be less than 5. */ if (o_ptr->pval < 5) o_ptr->pval = 5; /* Never exceed "value/difficulty" of 99. */ if (o_ptr->pval > 99) o_ptr->pval = 99; break; } } }
/* * Hack -- determine if a template is "good". * * Note that this test only applies to the object *kind*, so it is * possible to choose a kind which is "good", and then later cause * the actual object to be cursed. We do explicitly forbid objects * which are known to be boring or which start out somewhat damaged. */ static bool kind_is_good(const object_kind *kind) { /* Analyze the item type */ switch (kind->tval) { /* Armor -- Good unless damaged */ case TV_HARD_ARMOR: case TV_SOFT_ARMOR: case TV_DRAG_ARMOR: case TV_SHIELD: case TV_CLOAK: case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: { if (randcalc(kind->to_a, 0, MINIMISE) < 0) return (FALSE); return (TRUE); } /* Weapons -- Good unless damaged */ case TV_BOW: case TV_SWORD: case TV_HAFTED: case TV_POLEARM: case TV_DIGGING: { if (randcalc(kind->to_h, 0, MINIMISE) < 0) return (FALSE); if (randcalc(kind->to_d, 0, MINIMISE) < 0) return (FALSE); return (TRUE); } /* Ammo -- Arrows/Bolts are good */ case TV_BOLT: case TV_ARROW: { return (TRUE); } /* Books -- High level books are good */ case TV_MAGIC_BOOK: case TV_PRAYER_BOOK: { if (kind->sval >= SV_BOOK_MIN_GOOD) return (TRUE); return (FALSE); } /* Rings -- Rings of Speed are good */ case TV_RING: { if (kind->sval == SV_RING_SPEED) return (TRUE); return (FALSE); } /* Amulets -- Amulets of the Magi are good */ case TV_AMULET: { if (kind->sval == SV_AMULET_THE_MAGI) return (TRUE); if (kind->sval == SV_AMULET_DEVOTION) return (TRUE); if (kind->sval == SV_AMULET_WEAPONMASTERY) return (TRUE); if (kind->sval == SV_AMULET_TRICKERY) return (TRUE); return (FALSE); } } /* Assume not good */ return (FALSE); }