/** * 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 (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); }
/** * Add power for non-derived flags (derived flags have flag_power 0) */ static int flags_power(const object_type *obj, int p, int verbose, ang_file *log_file, bool known) { size_t i, j; int q; bitflag flags[OF_SIZE]; /* Extract the flags */ if (known) object_flags(obj, flags); else object_flags_known(obj, flags); /* Log the flags in human-readable form */ if (verbose) log_flags(flags, log_file); /* Zero the flag counts */ for (i = 0; i < N_ELEMENTS(flag_sets); i++) flag_sets[i].count = 0; for (i = of_next(flags, FLAG_START); i != FLAG_END; i = of_next(flags, i + 1)) { if (flag_power(i)) { q = (flag_power(i) * flag_slot_mult(i, wield_slot(obj))); p += q; log_obj(format("Add %d power for %s, total is %d\n", q, flag_name(i), p)); } /* Track combinations of flag types */ for (j = 0; j < N_ELEMENTS(flag_sets); j++) if (flag_sets[j].type == obj_flag_type(i)) flag_sets[j].count++; } /* Add extra power for multiple flags of the same type */ for (i = 0; i < N_ELEMENTS(flag_sets); i++) { if (flag_sets[i].count > 1) { q = (flag_sets[i].factor * flag_sets[i].count * flag_sets[i].count); p += q; log_obj(format("Add %d power for multiple %s, total is %d\n", q, flag_sets[i].desc, p)); } /* Add bonus if item has a full set of these flags */ if (flag_sets[i].count == flag_sets[i].size) { q = flag_sets[i].bonus; p += q; log_obj(format("Add %d power for full set of %s, total is %d\n", q, flag_sets[i].desc, p)); } } return p; }
/** * Notice things about an object that would be noticed in time. */ static void object_notice_after_time(void) { int i; int flag; object_type *o_ptr; char o_name[80]; bitflag f[OF_SIZE], timed_mask[OF_SIZE]; flags_init(timed_mask, OF_SIZE, OF_NOTICE_TIMED_MASK, FLAG_END); /* Check every item the player is wearing */ for (i = INVEN_WIELD; i < ALL_INVEN_TOTAL; i++) { o_ptr = &p_ptr->inventory[i]; if (!o_ptr->k_idx || object_is_known(o_ptr)) continue; /* Check for timed notice flags */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); object_flags(o_ptr, f); of_inter(f, timed_mask); for (flag = of_next(f, FLAG_START); flag != FLAG_END; flag = of_next(f, flag + 1)) { if (!of_has(o_ptr->known_flags, flag)) { /* Message */ if (!streq(msgs[flag], "")) msg_format(msgs[flag], o_name); /* Notice the flag */ object_notice_flag(o_ptr, flag); if (object_is_jewelry(o_ptr) && (!object_effect(o_ptr) || object_effect_is_known(o_ptr))) { /* XXX this is a small hack, but jewelry with anything noticeable really is obvious */ /* XXX except, wait until learn activation if that is only clue */ object_flavor_aware(o_ptr); object_check_for_ident(o_ptr); } } else { /* Notice the flag is absent */ object_notice_flag(o_ptr, flag); } } /* XXX Is this necessary? */ object_check_for_ident(o_ptr); } }
/** * Describe random powers on ego items * * \param tb is the description textblock we're building * \param ego is the ego type we're analysing */ static bool describe_ego(textblock *tb, const struct ego_item *ego) { if (ego && ego->num_randlines) { int i, of_type, tot = 0; bitflag f[OF_SIZE]; for (i = 0; i < ego->num_randlines; i++) { /* See whether we recognise the flagset for this choice */ of_type = obj_flag_type(of_next(ego->randmask[i], FLAG_START)); create_mask(f, FALSE, of_type, OFT_MAX); if (of_is_equal(f, ego->randmask[i])) { textblock_append(tb, "It provides %s random %s. ", ego->num_randflags[i] > 1 ? "more than one" : "one", obj_flagtype_name(of_type)); } else /* We don't, so count the number for later */ tot += ego->num_randflags[i]; } if (tot) textblock_append(tb, "It provides %s random power. ", tot > 1 ? "more than one" : "one"); return TRUE; } return FALSE; }
/** * This is a safe way to choose a random new flag to add to an object. * It takes the existing flags and an array of new flags, * and returns an entry from newf, or 0 if there are no * new flags available. */ static int get_new_attr(bitflag flags[OF_SIZE], bitflag newf[OF_SIZE]) { size_t i; int options = 0, flag = 0; for (i = of_next(newf, FLAG_START); i != FLAG_END; i = of_next(newf, i + 1)) { /* skip this one if the flag is already present */ if (of_has(flags, i)) continue; /* each time we find a new possible option, we have a 1-in-N chance of * choosing it and an (N-1)-in-N chance of keeping a previous one */ if (one_in_(++options)) flag = i; } return flag; }
/** * Apply minimum pvals to an ego item. Note that 0 is treated as meaning * "do not apply a minimum to this pval", so it leaves negative pvals alone. */ void ego_min_pvals(object_type *o_ptr) { int i, j, flag; if (!o_ptr->ego) return; for (i = 0; i < o_ptr->num_pvals; i++) for (j = 0; j < o_ptr->ego->num_pvals; j++) for (flag = of_next(o_ptr->ego->pval_flags[j], FLAG_START); flag != FLAG_END; flag = of_next(o_ptr->ego->pval_flags[j], flag + 1)) if (!of_has(o_ptr->flags, flag) || (o_ptr->ego->min_pval[j] != NO_MINIMUM && of_has(o_ptr->pval_flags[i], flag) && o_ptr->pval[i] < o_ptr->ego->min_pval[j])) object_add_pval(o_ptr, o_ptr->ego->min_pval[j] - o_ptr->pval[i], flag); }
/** * 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; }
/** * Apply an affix to an ego-item, checking minima as we go. * * \param o_ptr is the object we're modifying * \param level is the generation level * \param affix is the affix we're applying */ void ego_apply_magic(object_type *o_ptr, int level, int affix) { int i, j, flag, pval, amt; bitflag flags[OF_SIZE], f2[OF_SIZE]; ego_item_type *ego; ego = &e_info[affix]; /* Random powers */ for (i = 0; i < ego->num_randlines; i++) for (j = 0; j < ego->num_randflags[i]; j++) of_on(o_ptr->flags, get_new_attr(o_ptr->flags, ego->randmask[i])); /* Apply extra combat bonuses */ amt = randcalc(ego->to_h, level, RANDOMISE); o_ptr->to_h += amt; if (ego->min_to_h != NO_MINIMUM) { if (amt < ego->min_to_h) o_ptr->to_h += ego->min_to_h - amt; if (o_ptr->to_h < ego->min_to_h) o_ptr->to_h = ego->min_to_h; } amt = randcalc(ego->to_d, level, RANDOMISE); o_ptr->to_d += amt; if (ego->min_to_d != NO_MINIMUM) { if (amt < ego->min_to_d) o_ptr->to_d += ego->min_to_d - amt; if (o_ptr->to_d < ego->min_to_d) o_ptr->to_d = ego->min_to_d; } amt = randcalc(ego->to_a, level, RANDOMISE); o_ptr->to_a += amt; if (ego->min_to_a != NO_MINIMUM) { if (amt < ego->min_to_a) o_ptr->to_a += ego->min_to_a - amt; if (o_ptr->to_a < ego->min_to_a) o_ptr->to_a = ego->min_to_a; } /* Apply pvals */ of_copy(f2, ego->flags); for (i = 0; i < ego->num_pvals; i++) { of_copy(flags, ego->pval_flags[i]); pval = randcalc(ego->pval[i], level, RANDOMISE); if (ego->min_pval[i] != NO_MINIMUM && pval < ego->min_pval[i]) pval = ego->min_pval[i]; for (flag = of_next(flags, FLAG_START); flag != FLAG_END; flag = of_next(flags, flag + 1)) /* Prevent phantom flags, and check minima after adding */ if (pval) { object_add_pval(o_ptr, pval, flag); if (ego->min_pval[i] != NO_MINIMUM && of_has(o_ptr->flags, flag)) if (o_ptr->pval[which_pval(o_ptr, flag)] < ego->min_pval[i]) object_add_pval(o_ptr, ego->min_pval[i] - o_ptr->pval[which_pval(o_ptr, flag)], flag); } else of_off(f2, flag); } /* Apply remaining flags */ of_union(o_ptr->flags, f2); /* Adjust AC, weight, dice and sides */ if (o_ptr->ac && ego->ac_mod) o_ptr->ac = ((100 + ego->ac_mod) * o_ptr->ac) / 100; o_ptr->weight = ((100 + ego->wgt_mod) * o_ptr->weight) / 100; o_ptr->dd += ego->dd; if (o_ptr->dd < 1) o_ptr->dd = 1; o_ptr->ds += ego->ds; if (o_ptr->ds < 1) o_ptr->ds = 1; /* Tidy up and de-duplicate flags, and set the correct prefix/suffix */ check_flags(o_ptr); obj_affix_names(o_ptr); return; }
/** * Hit a trap. */ extern void hit_trap(int y, int x) { bool ident = false; struct trap *trap; struct effect *effect; /* Count the hidden traps here */ int num = num_traps(cave, y, x, -1); /* The player is safe from all traps */ if (player_is_trapsafe(player)) return; /* Oops. We've walked right into trouble. */ if (num == 1) msg("You stumble upon a trap!"); else if (num > 1) msg("You stumble upon some traps!"); /* Look at the traps in this grid */ for (trap = square_trap(cave, y, x); trap; trap = trap->next) { int flag; bool saved = false; /* Require that trap be capable of affecting the character */ if (!trf_has(trap->kind->flags, TRF_TRAP)) continue; if (trap->timeout) continue; /* Disturb the player */ disturb(player, 0); /* Give a message */ if (trap->kind->msg) msg(trap->kind->msg); /* Test for save due to flag */ for (flag = of_next(trap->kind->save_flags, FLAG_START); flag != FLAG_END; flag = of_next(trap->kind->save_flags, flag + 1)) if (player_of_has(player, flag)) { saved = true; equip_learn_flag(player, flag); } /* Test for save due to armor */ if (trf_has(trap->kind->flags, TRF_SAVE_ARMOR) && !trap_check_hit(125)) saved = true; /* Test for save due to saving throw */ if (trf_has(trap->kind->flags, TRF_SAVE_THROW) && (randint0(100) < player->state.skills[SKILL_SAVE])) saved = true; /* Save, or fire off the trap */ if (saved) { if (trap->kind->msg_good) msg(trap->kind->msg_good); } else { if (trap->kind->msg_bad) msg(trap->kind->msg_bad); effect = trap->kind->effect; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); /* Do any extra effects */ if (trap->kind->effect_xtra && one_in_(2)) { if (trap->kind->msg_xtra) msg(trap->kind->msg_xtra); effect = trap->kind->effect_xtra; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); } } /* Some traps drop you a dungeon level */ if (trf_has(trap->kind->flags, TRF_DOWN)) dungeon_change_level(player, dungeon_get_next_level(player->depth, 1)); /* Some traps drop you onto them */ if (trf_has(trap->kind->flags, TRF_PIT)) monster_swap(player->py, player->px, trap->fy, trap->fx); /* Some traps disappear after activating, all have a chance to */ if (trf_has(trap->kind->flags, TRF_ONETIME) || one_in_(3)) { square_destroy_trap(cave, y, x); square_forget(cave, y, x); } /* Trap may have gone */ if (!square_trap(cave, y, x)) break; /* Trap becomes visible (always XXX) */ trf_on(trap->flags, TRF_VISIBLE); square_memorize(cave, y, x); } /* Verify traps (remove marker if appropriate) */ (void)square_verify_trap(cave, y, x, 0); }