/** * Allow one item to "absorb" another, assuming they are similar. * * The blending of the "note" field assumes that either (1) one has an * inscription and the other does not, or (2) neither has an inscription. * In both these cases, we can simply use the existing note, unless the * blending object has a note, in which case we use that note. * * These assumptions are enforced by the "object_similar()" code. */ static void object_absorb_merge(struct object *obj1, const struct object *obj2) { int total; /* Blend all knowledge */ of_union(obj1->known_flags, obj2->known_flags); of_union(obj1->id_flags, obj2->id_flags); /* Merge inscriptions */ if (obj2->note) obj1->note = obj2->note; /* Combine timeouts for rod stacking */ if (tval_can_have_timeout(obj1)) obj1->timeout += obj2->timeout; /* Combine pvals for wands and staves */ if (tval_can_have_charges(obj1) || tval_is_money(obj1)) { total = obj1->pval + obj2->pval; obj1->pval = total >= MAX_PVAL ? MAX_PVAL : total; } /* Combine origin data as best we can */ if (obj1->origin != obj2->origin || obj1->origin_depth != obj2->origin_depth || obj1->origin_xtra != obj2->origin_xtra) { int act = 2; if (obj1->origin_xtra && obj2->origin_xtra) { monster_race *r_ptr = &r_info[obj1->origin_xtra]; monster_race *s_ptr = &r_info[obj2->origin_xtra]; bool r_uniq = rf_has(r_ptr->flags, RF_UNIQUE) ? TRUE : FALSE; bool s_uniq = rf_has(s_ptr->flags, RF_UNIQUE) ? TRUE : FALSE; if (r_uniq && !s_uniq) act = 0; else if (s_uniq && !r_uniq) act = 1; else act = 2; } switch (act) { /* Overwrite with obj2 */ case 1: { obj1->origin = obj2->origin; obj1->origin_depth = obj2->origin_depth; obj1->origin_xtra = obj2->origin_xtra; } /* Set as "mixed" */ case 2: { obj1->origin = ORIGIN_MIXED; } } } }
/* * Notice the ego on an ego item. */ void object_notice_ego(object_type *o_ptr) { ego_item_type *e_ptr; bitflag learned_flags[OF_SIZE]; bitflag xtra_flags[OF_SIZE]; if (!o_ptr->name2) return; e_ptr = &e_info[o_ptr->name2]; /* XXX Eddie print a message on notice ego if not already noticed? */ /* XXX Eddie should we do something about everseen of egos here? */ /* Learn ego flags */ of_union(o_ptr->known_flags, e_ptr->flags); /* Learn all flags except random abilities */ of_setall(learned_flags); switch (e_ptr->xtra) { case OBJECT_XTRA_TYPE_NONE: break; case OBJECT_XTRA_TYPE_SUSTAIN: set_ego_xtra_sustain(xtra_flags); of_diff(learned_flags, xtra_flags); break; case OBJECT_XTRA_TYPE_RESIST: set_ego_xtra_resist(xtra_flags); of_diff(learned_flags, xtra_flags); break; case OBJECT_XTRA_TYPE_POWER: set_ego_xtra_power(xtra_flags); of_diff(learned_flags, xtra_flags); break; default: assert(0); } of_union(o_ptr->known_flags, learned_flags); if (object_add_ident_flags(o_ptr, IDENT_NAME)) { /* if you know the ego, you know which it is of excellent or splendid */ object_notice_sensing(o_ptr); object_check_for_ident(o_ptr); } }
/* * Create the artifact with the specified number */ static void wiz_create_artifact(int a_idx) { object_type *i_ptr; object_type object_type_body; int k_idx; artifact_type *a_ptr = &a_info[a_idx]; /* Ignore "empty" artifacts */ if (!a_ptr->name) return; /* Get local object */ i_ptr = &object_type_body; /* Wipe the object */ object_wipe(i_ptr); /* Acquire the "kind" index */ k_idx = lookup_kind(a_ptr->tval, a_ptr->sval); /* Oops */ if (!k_idx) return; /* Create the artifact */ object_prep(i_ptr, &k_info[k_idx], a_ptr->alloc_min, RANDOMISE); /* Save the name */ i_ptr->name1 = a_idx; /* Extract the fields */ i_ptr->pval = a_ptr->pval; i_ptr->ac = a_ptr->ac; i_ptr->dd = a_ptr->dd; i_ptr->ds = a_ptr->ds; i_ptr->to_a = a_ptr->to_a; i_ptr->to_h = a_ptr->to_h; i_ptr->to_d = a_ptr->to_d; i_ptr->weight = a_ptr->weight; /* Hack -- extract the "cursed" flags */ if (cursed_p(a_ptr)) { bitflag curse_flags[OF_SIZE]; of_copy(curse_flags, a_ptr->flags); flags_mask(curse_flags, OF_SIZE, OF_CURSE_MASK, FLAG_END); of_union(i_ptr->flags, curse_flags); } /* Mark that the artifact has been created. */ a_ptr->created = TRUE; /* Mark as cheat */ i_ptr->origin = ORIGIN_CHEAT; /* Drop the artifact from heaven */ drop_near(i_ptr, 0, p_ptr->py, p_ptr->px, TRUE); /* All done */ msg_print("Allocated."); }
/** * Copy artifact data to a normal object, and set various slightly hacky * globals. */ static void copy_artifact_data(object_type *o_ptr, const artifact_type *a_ptr) { /* Extract the other fields */ o_ptr->pval = a_ptr->pval; o_ptr->ac = a_ptr->ac; o_ptr->dd = a_ptr->dd; o_ptr->ds = a_ptr->ds; o_ptr->to_a = a_ptr->to_a; o_ptr->to_h = a_ptr->to_h; o_ptr->to_d = a_ptr->to_d; o_ptr->weight = a_ptr->weight; /* Hack -- extract the "cursed" flags */ if (cursed_p(a_ptr)) { bitflag curse_flags[OF_SIZE]; of_copy(curse_flags, a_ptr->flags); flags_mask(curse_flags, OF_SIZE, OF_CURSE_MASK, FLAG_END); of_union(o_ptr->flags, curse_flags); } /* Mega-Hack -- increase the rating */ rating += 10; /* Mega-Hack -- increase the rating again */ if (a_ptr->cost > 50000L) rating += 10; /* Set the good item flag */ good_item_flag = TRUE; /* Cheat -- peek at the item */ if (OPT(cheat_peek)) object_mention(o_ptr); }
/** * Copy artifact data to a normal object, and set various slightly hacky * globals. */ static void copy_artifact_data(object_type *o_ptr, const artifact_type *a_ptr) { /* Extract the other fields */ o_ptr->pval = a_ptr->pval; o_ptr->ac = a_ptr->ac; o_ptr->dd = a_ptr->dd; o_ptr->ds = a_ptr->ds; o_ptr->to_a = a_ptr->to_a; o_ptr->to_h = a_ptr->to_h; o_ptr->to_d = a_ptr->to_d; o_ptr->weight = a_ptr->weight; /* Hack -- extract the "cursed" flags */ if (cursed_p(a_ptr)) { bitflag curse_flags[OF_SIZE]; of_copy(curse_flags, a_ptr->flags); flags_mask(curse_flags, OF_SIZE, OF_CURSE_MASK, FLAG_END); of_union(o_ptr->flags, curse_flags); } /* Mega-Hack -- increase the level rating * - a sizeable increase for any artifact (c.f. up to 30 for ego items) * - a bigger increase for more powerful artifacts */ rating += 30; rating += object_power(o_ptr, FALSE, NULL, TRUE) / 25; /* Set the good item flag */ good_item_flag = TRUE; /* Cheat -- peek at the item */ if (OPT(cheat_peek)) object_mention(o_ptr); }
/** * Copy artifact data to a normal object, and set various slightly hacky * globals. */ void copy_artifact_data(object_type *o_ptr, const artifact_type *a_ptr) { int i; /* Extract the data */ for (i = 0; i < a_ptr->num_pvals; i++) if (a_ptr->pval[i]) { o_ptr->pval[i] = a_ptr->pval[i]; of_copy(o_ptr->pval_flags[i], a_ptr->pval_flags[i]); } o_ptr->num_pvals = a_ptr->num_pvals; o_ptr->ac = a_ptr->ac; o_ptr->dd = a_ptr->dd; o_ptr->ds = a_ptr->ds; o_ptr->to_a = a_ptr->to_a; o_ptr->to_h = a_ptr->to_h; o_ptr->to_d = a_ptr->to_d; o_ptr->weight = a_ptr->weight; of_union(o_ptr->flags, a_ptr->flags); /* Set the prefix or suffix, if the artifact has an affix */ if (a_ptr->affix && affix_is_prefix(a_ptr->affix->eidx)) o_ptr->prefix = a_ptr->affix; if (a_ptr->affix && affix_is_suffix(a_ptr->affix->eidx)) o_ptr->suffix = a_ptr->affix; /* Set the theme, if it has one */ if (a_ptr->theme) o_ptr->theme = a_ptr->theme; }
/** * Provide information on an ego-item type */ textblock *object_info_ego(struct ego_item * ego) { object_kind *kind = NULL; object_type obj = { 0 }; int i; for (i = 0; i < z_info->k_max; i++) { kind = &k_info[i]; if (!kind->name) continue; if (kind->tval == ego->tval[0]) break; } obj.kind = kind; obj.tval = kind->tval; obj.sval = kind->sval; obj.name2 = ego->eidx; of_union(obj.flags_obj, ego->flags_obj); cf_union(obj.flags_curse, ego->flags_curse); for (i = 0; i < MAX_P_RES; i++) obj.percent_res[i] = ego->percent_res[i]; for (i = 0; i < A_MAX; i++) obj.bonus_stat[i] = ego->bonus_stat[i]; for (i = 0; i < MAX_P_BONUS; i++) obj.bonus_other[i] = ego->bonus_other[i]; for (i = 0; i < MAX_P_SLAY; i++) obj.multiple_slay[i] = ego->multiple_slay[i]; for (i = 0; i < MAX_P_BRAND; i++) obj.multiple_brand[i] = ego->multiple_brand[i]; return object_info_out(&obj, OINFO_FULL | OINFO_EGO | OINFO_DUMMY); }
/** * 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); }
/** * Copy artifact data to a normal object, and set various slightly hacky * globals. */ void copy_artifact_data(struct object *obj, const struct artifact *art) { int i; /* Extract the data */ for (i = 0; i < OBJ_MOD_MAX; i++) obj->modifiers[i] = art->modifiers[i]; obj->ac = art->ac; obj->dd = art->dd; obj->ds = art->ds; obj->to_a = art->to_a; obj->to_h = art->to_h; obj->to_d = art->to_d; obj->weight = art->weight; obj->activation = art->activation; if (art->time.base != 0) obj->time = art->time; of_union(obj->flags, art->flags); copy_slay(&obj->slays, art->slays); copy_brand(&obj->brands, art->brands); for (i = 0; i < ELEM_MAX; i++) { /* Take the larger of artifact and base object resist levels */ obj->el_info[i].res_level = MAX(art->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 |= art->el_info[i].flags; } }
/** * 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; }
/** * Label an item as an ego item if it has the required flags */ void label_as_ego(object_type * o_ptr, int item) { char o_name[120]; int j; int temp_flag; ego_item_type *e_ptr = &e_info[o_ptr->name2]; /* All ego object flags now known */ of_union(o_ptr->id_obj, e_ptr->flags_obj); /* All shown curses are now known */ if (of_has(e_ptr->flags_obj, OF_SHOW_CURSE)) cf_union(o_ptr->id_curse, e_ptr->flags_curse); /* Know all ego resists */ for (j = 0; j < MAX_P_RES; j++) { temp_flag = OBJECT_ID_BASE_RESIST + j; if (e_ptr->percent_res[j] != RES_LEVEL_BASE) if_on(o_ptr->id_other, temp_flag); } /* Know all ego slays */ for (j = 0; j < MAX_P_SLAY; j++) { temp_flag = OBJECT_ID_BASE_SLAY + j; if (e_ptr->multiple_slay[j] != MULTIPLE_BASE) if_on(o_ptr->id_other, temp_flag); } /* Know all ego brands */ for (j = 0; j < MAX_P_BRAND; j++) { temp_flag = OBJECT_ID_BASE_BRAND + j; if (e_ptr->multiple_brand[j] != MULTIPLE_BASE) if_on(o_ptr->id_other, temp_flag); } /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Redraw stuff */ p_ptr->redraw |= (PR_INVEN | PR_EQUIP | PR_BASIC | PR_EXTRA); /* Handle stuff */ handle_stuff(p_ptr); /* Description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe */ if (item - 1 >= INVEN_WIELD) { char *m = format("%s: %s (%c).", describe_use(item - 1), o_name, index_to_label(item - 1)); my_strcap(m); msg(m); } else if (item - 1 >= 0) { msg("In your pack: %s (%c).", o_name, index_to_label(item)); } }
/* * Notice a set of flags - returns TRUE if anything new was learned */ bool object_notice_flags(object_type *o_ptr, bitflag flags[OF_SIZE]) { if (!of_is_subset(o_ptr->known_flags, flags)) { of_union(o_ptr->known_flags, flags); /* XXX Eddie don't want infinite recursion if object_check_for_ident sets more flags, * but maybe this will interfere with savefile repair */ object_check_for_ident(o_ptr); event_signal(EVENT_INVENTORY); event_signal(EVENT_EQUIPMENT); return TRUE; } return FALSE; }
/** * 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; }
/** * Copy artifact data to a normal object, and set various slightly hacky * globals. */ void copy_artifact_data(object_type *o_ptr, const artifact_type *a_ptr) { int i; /* Extract the data */ for (i = 0; i < a_ptr->num_pvals; i++) if (a_ptr->pval[i]) { o_ptr->pval[i] = a_ptr->pval[i]; of_copy(o_ptr->pval_flags[i], a_ptr->pval_flags[i]); } o_ptr->num_pvals = a_ptr->num_pvals; o_ptr->ac = a_ptr->ac; o_ptr->dd = a_ptr->dd; o_ptr->ds = a_ptr->ds; o_ptr->to_a = a_ptr->to_a; o_ptr->to_h = a_ptr->to_h; o_ptr->to_d = a_ptr->to_d; o_ptr->weight = a_ptr->weight; of_union(o_ptr->flags, a_ptr->flags); }
/** * Provide information on an ego-item type */ textblock *object_info_ego(struct ego_item *ego) { object_kind *kind = NULL; object_type obj = { 0 }; int i; for (i = 0; i < z_info->k_max; i++) { kind = &k_info[i]; if (!kind->name) continue; if (kind->tval == ego->tval[0]) break; } obj.kind = kind; obj.tval = kind->tval; obj.sval = kind->sval; obj.ego = ego; of_union(obj.flags, ego->flags); return object_info_out(&obj, OINFO_FULL | OINFO_EGO | OINFO_DUMMY); }
/* * Describe combat advantages. */ static bool describe_combat(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { bool full = mode & OINFO_FULL; const char *desc[SL_MAX] = { 0 }; int i; int mult[SL_MAX]; int cnt, dam, total_dam, plus = 0; int xtra_postcrit = 0, xtra_precrit = 0; int crit_mult, crit_div, crit_add; int str_plus, dex_plus, old_blows = 0, new_blows, extra_blows; int str_faster = -1, str_done = -1; object_type *bow = &p_ptr->inventory[INVEN_BOW]; bitflag f[OF_SIZE], tmp_f[OF_SIZE], mask[OF_SIZE]; bool weapon = (wield_slot(o_ptr) == INVEN_WIELD); bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) && (bow->kind); int multiplier = 1; /* Create the "all slays" mask */ create_mask(mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); /* Abort if we've nothing to say */ if (mode & OINFO_DUMMY) return FALSE; if (!weapon && !ammo) { /* Potions can have special text */ if (o_ptr->tval != TV_POTION || o_ptr->dd == 0 || o_ptr->ds == 0 || !object_flavor_is_aware(o_ptr)) return FALSE; textblock_append(tb, "It can be thrown at creatures with damaging effect.\n"); return TRUE; } if (full) { object_flags(o_ptr, f); } else { object_flags_known(o_ptr, f); } textblock_append_c(tb, TERM_L_WHITE, "Combat info:\n"); if (weapon) { /* * Get the player's hypothetical state, were they to be * wielding this item. */ player_state state; int dex_plus_bound; int str_plus_bound; object_type inven[INVEN_TOTAL]; memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type)); inven[INVEN_WIELD] = *o_ptr; if (full) object_know_all_flags(&inven[INVEN_WIELD]); calc_bonuses(inven, &state, TRUE); dex_plus_bound = STAT_RANGE - state.stat_ind[A_DEX]; str_plus_bound = STAT_RANGE - state.stat_ind[A_STR]; dam = ((o_ptr->ds + 1) * o_ptr->dd * 5); xtra_postcrit = state.dis_to_d * 10; if (object_attack_plusses_are_visible(o_ptr)) { xtra_precrit += o_ptr->to_d * 10; plus += o_ptr->to_h; } calculate_melee_crits(&state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); /* Warn about heavy weapons */ if (adj_str_hold[state.stat_ind[A_STR]] < o_ptr->weight / 10) textblock_append_c(tb, TERM_L_RED, "You are too weak to use this weapon.\n"); textblock_append_c(tb, TERM_L_GREEN, "%d.%d ", state.num_blows / 100, (state.num_blows / 10) % 10); textblock_append(tb, "blow%s/round.\n", (state.num_blows > 100) ? "s" : ""); /* Check to see if extra STR or DEX would yield extra blows */ old_blows = state.num_blows; extra_blows = 0; /* First we need to look for extra blows on other items, as * state does not track these */ for (i = INVEN_BOW; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); if (of_has(tmp_f, OF_BLOWS)) extra_blows += p_ptr->inventory[i].pval[which_pval(&p_ptr->inventory[i], OF_BLOWS)]; } /* Then we add blows from the weapon being examined */ if (of_has(f, OF_BLOWS)) extra_blows += o_ptr->pval[which_pval(o_ptr, OF_BLOWS)]; /* Then we check for extra "real" blows */ for (dex_plus = 0; dex_plus < dex_plus_bound; dex_plus++) { for (str_plus = 0; str_plus < str_plus_bound; str_plus++) { state.stat_ind[A_STR] += str_plus; state.stat_ind[A_DEX] += dex_plus; new_blows = calc_blows(o_ptr, &state, extra_blows); /* Test to make sure that this extra blow is a * new str/dex combination, not a repeat */ if ((new_blows - new_blows % 10) > (old_blows - old_blows % 10) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would get %d.%d blows\n", str_plus, dex_plus, (new_blows / 100), (new_blows / 10) % 10); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_done = str_plus; break; } /* If the combination doesn't increment * the displayed blows number, it might still * take a little less energy */ if (new_blows > old_blows && (str_plus < str_faster || str_faster == -1) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would attack a bit faster\n", str_plus, dex_plus); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_faster = str_plus; continue; } state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; } } } else { int tdis = 6 + 2 * p_ptr->state.ammo_mult; if (object_attack_plusses_are_visible(o_ptr)) plus += o_ptr->to_h; calculate_missile_crits(&p_ptr->state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); /* Calculate damage */ dam = ((o_ptr->ds + 1) * o_ptr->dd * 5); if (object_attack_plusses_are_visible(o_ptr)) dam += (o_ptr->to_d * 10); if (object_attack_plusses_are_visible(bow)) dam += (bow->to_d * 10); /* Apply brands/slays from the shooter to the ammo, but only if known * Note that this is not dependent on mode, so that viewing shop-held * ammo (fully known) does not leak information about launcher */ object_flags_known(bow, tmp_f); of_union(f, tmp_f); textblock_append(tb, "Hits targets up to "); textblock_append_c(tb, TERM_L_GREEN, format("%d", tdis * 10)); textblock_append(tb, " feet away.\n"); } /* Collect slays */ /* Melee weapons get slays and brands from other items now */ if (weapon) { bool nonweap = FALSE; for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); of_inter(tmp_f, mask); /* strip out non-slays */ if (of_union(f, tmp_f)) nonweap = TRUE; } if (nonweap) textblock_append(tb, "This weapon may benefit from one or more off-weapon brands or slays.\n"); } textblock_append(tb, "Average damage/round: "); if (ammo) multiplier = p_ptr->state.ammo_mult; cnt = list_slays(f, mask, desc, NULL, mult, TRUE); for (i = 0; i < cnt; i++) { int melee_adj_mult = ammo ? 0 : 1; /* ammo mult adds fully, melee mult is times 1, so adds 1 less */ /* Include bonus damage and slay in stated average */ total_dam = dam * (multiplier + mult[i] - melee_adj_mult) + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); textblock_append(tb, " vs. %s, ", desc[i]); } if (cnt) textblock_append(tb, "and "); /* Include bonus damage in stated average */ total_dam = dam * multiplier + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); if (cnt) textblock_append(tb, " vs. others"); textblock_append(tb, ".\n"); /* Note the impact flag */ if (of_has(f, OF_IMPACT)) textblock_append(tb, "Sometimes creates earthquakes on impact.\n"); /* Add breakage chance */ if (ammo) { int chance = breakage_chance(o_ptr, TRUE); textblock_append_c(tb, TERM_L_GREEN, "%d%%", chance); textblock_append(tb, " chance of breaking upon contact.\n"); } /* You always have something to say... */ return TRUE; }
/* * Describe damage. */ static bool describe_damage(textblock *tb, const object_type *o_ptr, player_state state, bitflag f[OF_SIZE], oinfo_detail_t mode) { const char *desc[SL_MAX] = { 0 }; size_t i, cnt; int mult[SL_MAX]; int dice, sides, dam, total_dam, plus = 0; int xtra_postcrit = 0, xtra_precrit = 0; int crit_mult, crit_div, crit_add; int old_blows = 0; object_type *bow = &p_ptr->inventory[INVEN_BOW]; bitflag tmp_f[OF_SIZE], mask[OF_SIZE]; bool weapon = (wield_slot(o_ptr) == INVEN_WIELD); bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) && (bow->kind); int multiplier = 1; bool full = mode & OINFO_FULL; /* Create the "all slays" mask */ create_mask(mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); /* Use displayed dice if real dice not known */ if (full || object_attack_plusses_are_visible(o_ptr)) { dice = o_ptr->dd; sides = o_ptr->ds; } else { dice = o_ptr->kind->dd; sides = o_ptr->kind->ds; } /* Calculate damage */ dam = ((sides + 1) * dice * 5); if (weapon) { xtra_postcrit = state.dis_to_d * 10; if (object_attack_plusses_are_visible(o_ptr) || full) { xtra_precrit += o_ptr->to_d * 10; plus += o_ptr->to_h; } calculate_melee_crits(&state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); old_blows = state.num_blows; } else { /* Ammo */ if (object_attack_plusses_are_visible(o_ptr) || full) plus += o_ptr->to_h; calculate_missile_crits(&p_ptr->state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); if (object_attack_plusses_are_visible(o_ptr) || full) dam += (o_ptr->to_d * 10); if (object_attack_plusses_are_visible(bow)) dam += (bow->to_d * 10); /* Apply brands/slays from the shooter to the ammo, but only if known * Note that this is not dependent on mode, so that viewing shop-held * ammo (fully known) does not leak information about launcher */ object_flags_known(bow, tmp_f); of_union(f, tmp_f); } /* Collect slays */ /* Melee weapons get slays and brands from other items now */ if (weapon) { bool nonweap_slay = FALSE; for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); /* Strip out non-slays */ of_inter(tmp_f, mask); if (of_union(f, tmp_f)) nonweap_slay = TRUE; } if (nonweap_slay) textblock_append(tb, "This weapon may benefit from one or more off-weapon brands or slays.\n"); } textblock_append(tb, "Average damage/round: "); if (ammo) multiplier = p_ptr->state.ammo_mult; /* Output damage for creatures effected by the brands or slays */ cnt = list_slays(f, mask, desc, NULL, mult, TRUE); for (i = 0; i < cnt; i++) { /* ammo mult adds fully, melee mult is times 1, so adds 1 less */ int melee_adj_mult = ammo ? 0 : 1; /* Include bonus damage and slay in stated average */ total_dam = dam * (multiplier + mult[i] - melee_adj_mult) + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); textblock_append(tb, " vs. %s, ", desc[i]); } if (cnt) textblock_append(tb, "and "); /* Include bonus damage in stated average */ total_dam = dam * multiplier + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; /* Normal damage, not considering brands or slays */ if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); if (cnt) textblock_append(tb, " vs. others"); textblock_append(tb, ".\n"); return TRUE; }
/* XXX Eddie should messages be adhoc all over the place? perhaps the main * loop should check for change in inventory/wieldeds and all messages be * printed from one place */ void object_notice_on_wield(object_type *o_ptr) { bitflag f[OF_SIZE], obvious_mask[OF_SIZE]; bool obvious = FALSE; const slay_t *s_ptr; flags_init(obvious_mask, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); /* Save time of wield for later */ object_last_wield = turn; /* Only deal with un-ID'd items */ if (object_is_known(o_ptr)) return; /* Wear it */ object_flavor_tried(o_ptr); if (object_add_ident_flags(o_ptr, IDENT_WORN)) object_check_for_ident(o_ptr); if (obj_is_light(o_ptr) && ego_item_p(o_ptr)) object_notice_ego(o_ptr); if (object_flavor_is_aware(o_ptr) && easy_know(o_ptr)) { object_notice_everything(o_ptr); return; } /* Automatically sense artifacts upon wield */ object_sense_artifact(o_ptr); /* Note artifacts when found */ if (artifact_p(o_ptr)) history_add_artifact(o_ptr->name1, object_is_known(o_ptr), TRUE); /* special case FA, needed at least for mages wielding gloves */ if (object_FA_would_be_obvious(o_ptr)) of_on(obvious_mask, OF_FREE_ACT); /* Learn about obvious flags */ of_union(o_ptr->known_flags, obvious_mask); /* Extract the flags */ object_flags(o_ptr, f); /* Find obvious things (disregarding curses) */ flags_clear(obvious_mask, OF_SIZE, OF_CURSE_MASK, FLAG_END); if (of_is_inter(f, obvious_mask)) obvious = TRUE; flags_init(obvious_mask, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); /* XXX Eddie should these next NOT call object_check_for_ident due to worries about repairing? */ /* XXX Eddie this is a small hack, but jewelry with anything noticeable really is obvious */ /* XXX Eddie learn =soulkeeping vs =bodykeeping when notice sustain_str */ if (object_is_jewelry(o_ptr)) { /* Learn the flavor of jewelry with obvious flags */ if (EASY_LEARN && obvious) object_flavor_aware(o_ptr); /* Learn all flags on any aware non-artifact jewelry */ if (object_flavor_is_aware(o_ptr) && !artifact_p(o_ptr)) object_know_all_flags(o_ptr); } object_check_for_ident(o_ptr); if (!obvious) return; /* Messages */ for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++) { if (of_has(f, s_ptr->slay_flag) && s_ptr->brand) { char o_name[40]; object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); msg_format("Your %s %s!", o_name, s_ptr->active_verb); } } /* XXX Eddie need to add stealth here, also need to assert/double-check everything is covered */ if (of_has(f, OF_STR)) msg_format("You feel %s!", o_ptr->pval > 0 ? "stronger" : "weaker"); if (of_has(f, OF_INT)) msg_format("You feel %s!", o_ptr->pval > 0 ? "smarter" : "more stupid"); if (of_has(f, OF_WIS)) msg_format("You feel %s!", o_ptr->pval > 0 ? "wiser" : "more naive"); if (of_has(f, OF_DEX)) msg_format("You feel %s!", o_ptr->pval > 0 ? "more dextrous" : "clumsier"); if (of_has(f, OF_CON)) msg_format("You feel %s!", o_ptr->pval > 0 ? "healthier" : "sicklier"); if (of_has(f, OF_CHR)) msg_format("You feel %s!", o_ptr->pval > 0 ? "cuter" : "uglier"); if (of_has(f, OF_SPEED)) msg_format("You feel strangely %s.", o_ptr->pval > 0 ? "quick" : "sluggish"); if (flags_test(f, OF_SIZE, OF_BLOWS, OF_SHOTS, FLAG_END)) msg_format("Your hands %s", o_ptr->pval > 0 ? "tingle!" : "ache."); if (of_has(f, OF_INFRA)) msg_format("Your eyes tingle."); if (of_has(f, OF_LIGHT)) msg_print("It glows!"); if (of_has(f, OF_TELEPATHY)) msg_print("Your mind feels strangely sharper!"); /* WARNING -- masking f by obvious mask -- this should be at the end of this function */ flags_mask(f, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); /* learn the ego on any obvious brand or slay */ if (EASY_LEARN && ego_item_p(o_ptr) && obvious && flags_test(f, OF_SIZE, OF_ALL_SLAY_MASK, FLAG_END)) object_notice_ego(o_ptr); /* Remember the flags */ object_notice_sensing(o_ptr); /* XXX Eddie should we check_for_ident here? */ }
/** * 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; }
/** * Carry an object and delete it. */ extern void py_pickup_aux(int o_idx, bool msg) { int slot, quiver_slot = 0; char o_name[120]; object_type *o_ptr = &o_list[o_idx]; object_type *i_ptr = &p_ptr->inventory[INVEN_LIGHT]; bitflag f[OF_SIZE], obvious_mask[OF_SIZE]; flags_init(obvious_mask, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); of_copy(f, o_ptr->flags_obj); /* 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_quiver_obj(o_ptr)) { int i; for (i = QUIVER_START; i < QUIVER_END; i++) { if (!p_ptr->inventory[i].k_idx) continue; if (!object_similar(&p_ptr->inventory[i], o_ptr, OSTACK_QUIVER)) continue; quiver_slot = i; break; } } /* Get the object again */ o_ptr = &p_ptr->inventory[slot]; /* Set squelch status */ p_ptr->notice |= PN_SQUELCH; /* Stone of Lore gives id on pickup */ if (!object_known_p(o_ptr)) { if (i_ptr->sval == SV_STONE_LORE) identify_object(o_ptr); /* Otherwise pseudo-ID */ else { bool heavy = FALSE; int feel; /* Heavy sensing */ heavy = (player_has(PF_PSEUDO_ID_HEAVY)); /* Type of feeling */ feel = (heavy ? value_check_aux1(o_ptr) : value_check_aux2(o_ptr)); /* We have "felt" it */ o_ptr->ident |= (IDENT_SENSE); /* Inscribe it textually */ o_ptr->feel = feel; /* Set squelch flag as appropriate */ p_ptr->notice |= PN_SQUELCH; } } /* Log artifacts if found */ if (artifact_p(o_ptr)) history_add_artifact(o_ptr->name1, object_is_known(o_ptr), TRUE); /* Notice dice and other obvious stuff */ notice_other(IF_DD_DS, slot + 1); (void) of_inter(f, obvious_mask); of_union(o_ptr->id_obj, f); /* Average things are average */ if ((o_ptr->feel == FEEL_AVERAGE) && (is_weapon(o_ptr) || is_armour(o_ptr))){ notice_other(IF_AC, slot + 1); notice_other(IF_TO_A, slot + 1); notice_other(IF_TO_H, slot + 1); notice_other(IF_TO_D, slot + 1); } /* Recalculate the bonuses */ p_ptr->update |= (PU_BONUS); /* Optionally, display a message */ if (msg && !quiver_slot) { /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Message */ msg_format("You have %s (%c).", o_name, index_to_label(slot)); } /* Delete the object */ delete_object_idx(o_idx); /* If we have a quiver slot that this item matches, use it */ if (quiver_slot) wield_item(o_ptr, slot, quiver_slot); }
/** * Complete object creation by applying magic to it. * * Magic includes rolling for random bonuses, applying flags to ego-items, * charging charged items, fuelling lights, and trapping chests. * * The `good` argument forces the item to be at least `good`, and the `great` * argument does likewise. Setting `allow_artifacts` to TRUE allows artifacts * to be created here. * * If `good` or `great` are not set, then the `lev` argument controls the * quality of item. See the function itself for the specifics of the * calculations involved. */ void apply_magic(object_type *o_ptr, int lev, bool allow_artifacts, bool good, bool great) { int power = 0; /*u32b xtra = 0;*/ /*bool new = FALSE;*/ /* Chance of being `good` and `great` */ int good_chance = (lev+2) * 3; int great_chance = MIN(lev/4 + lev, 50); /* Limit depth */ if (lev > MAX_DEPTH - 1) lev = MAX_DEPTH - 1; /* Roll for "good" */ if (good || (randint0(100) < good_chance)) { /* Assume "good" */ power = 1; /* Roll for "great" */ if (great || (randint0(100) < great_chance)) power = 2; } /* Roll for "cursed" */ else if (randint0(100) < good_chance) { /* Assume "cursed" */ power = -1; /* Roll for "broken" */ if (randint0(100) < great_chance) power = -2; } /* Roll for artifact creation */ if (allow_artifacts) { int i; int rolls = 0; /* Get one roll if excellent */ if (power >= 2) rolls = 1; /* Get four rolls if forced great */ if (great) rolls = 4; /* Roll for artifacts if allowed */ for (i = 0; i < rolls; i++) { if (make_artifact(o_ptr)) return; } } /* Apply magic */ switch (o_ptr->tval) { case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_BOW: case TV_SHOT: case TV_ARROW: case TV_BOLT: { if (power == 2 || power == -2) { int ego_power; ego_power = make_ego_item(o_ptr, lev, (bool)(power > 0)); if (ego_power) power = ego_power; } if (power) a_m_aux_1(o_ptr, lev, power); break; } case TV_DRAG_ARMOR: case TV_HARD_ARMOR: case TV_SOFT_ARMOR: case TV_SHIELD: case TV_HELM: case TV_CROWN: case TV_CLOAK: case TV_GLOVES: case TV_BOOTS: { if (power == 2 || power == -2) { int ego_power; ego_power = make_ego_item(o_ptr, lev, (bool)(power > 0)); if (ego_power) power = ego_power; } if (power) a_m_aux_2(o_ptr, lev, power); break; } case TV_RING: case TV_AMULET: { if (!power && (randint0(100) < 50)) power = -1; a_m_aux_3(o_ptr, lev, power); break; } case TV_LIGHT: { if (power == 2 || power == -2) make_ego_item(o_ptr, lev, (bool)(power > 0)); /* Fuel it */ a_m_aux_4(o_ptr, lev, power); break; } default: { a_m_aux_4(o_ptr, lev, power); break; } } /* Hack -- analyze ego-items */ if (o_ptr->name2) { ego_item_type *e_ptr = &e_info[o_ptr->name2]; bitflag flags[OF_SIZE]; object_flags(o_ptr, flags); /* Extra powers */ if (e_ptr->xtra == OBJECT_XTRA_TYPE_SUSTAIN) of_on(o_ptr->flags, get_new_attr(flags, ego_sustains, N_ELEMENTS(ego_sustains))); else if (e_ptr->xtra == OBJECT_XTRA_TYPE_RESIST) of_on(o_ptr->flags, get_new_attr(flags, ego_resists, N_ELEMENTS(ego_resists))); else if (e_ptr->xtra == OBJECT_XTRA_TYPE_POWER) of_on(o_ptr->flags, get_new_attr(flags, ego_powers, N_ELEMENTS(ego_powers))); /* Hack -- acquire "cursed" flags */ if (cursed_p(e_ptr)) { bitflag curse_flags[OF_SIZE]; of_copy(curse_flags, e_ptr->flags); flags_mask(curse_flags, OF_SIZE, OF_CURSE_MASK, FLAG_END); of_union(o_ptr->flags, curse_flags); } /* Hack -- apply extra penalties if needed */ if (cursed_p(o_ptr)) { /* Apply extra ego bonuses */ o_ptr->to_h -= randcalc(e_ptr->to_h, lev, RANDOMISE); o_ptr->to_d -= randcalc(e_ptr->to_d, lev, RANDOMISE); o_ptr->to_a -= randcalc(e_ptr->to_a, lev, RANDOMISE); /* Apply ego pval */ o_ptr->pval -= randcalc(e_ptr->pval, lev, RANDOMISE); /* Apply minimums */ if (o_ptr->to_h > -1 * e_ptr->min_to_h) o_ptr->to_h = -1 * e_ptr->min_to_h; if (o_ptr->to_d > -1 * e_ptr->min_to_d) o_ptr->to_d = -1 * e_ptr->min_to_d; if (o_ptr->to_a > -1 * e_ptr->min_to_a) o_ptr->to_a = -1 * e_ptr->min_to_a; if (o_ptr->pval > -1 * e_ptr->min_pval) o_ptr->pval = -1 * e_ptr->min_pval; } /* Hack -- apply extra bonuses if needed */ else { /* Apply extra ego bonuses */ o_ptr->to_h += randcalc(e_ptr->to_h, lev, RANDOMISE); o_ptr->to_d += randcalc(e_ptr->to_d, lev, RANDOMISE); o_ptr->to_a += randcalc(e_ptr->to_a, lev, RANDOMISE); /* Apply ego pval */ o_ptr->pval += randcalc(e_ptr->pval, lev, RANDOMISE); /* Apply minimums */ if (o_ptr->to_h < e_ptr->min_to_h) o_ptr->to_h = e_ptr->min_to_h; if (o_ptr->to_d < e_ptr->min_to_d) o_ptr->to_d = e_ptr->min_to_d; if (o_ptr->to_a < e_ptr->min_to_a) o_ptr->to_a = e_ptr->min_to_a; if (o_ptr->pval < e_ptr->min_pval) o_ptr->pval = e_ptr->min_pval; } /* Hack -- apply rating bonus */ rating += e_ptr->rating; /* Cheat -- describe the item */ if (OPT(cheat_peek)) object_mention(o_ptr); /* Done */ return; } /* Examine real objects */ if (o_ptr->k_idx) { object_kind *k_ptr = &k_info[o_ptr->k_idx]; /* Hack -- acquire "cursed" flag */ if (cursed_p(k_ptr)) { bitflag curse_flags[OF_SIZE]; of_copy(curse_flags, k_ptr->flags); flags_mask(curse_flags, OF_SIZE, OF_CURSE_MASK, FLAG_END); of_union(o_ptr->flags, curse_flags); } } }
/* * Calculate the players current "state", taking into account * not only race/class intrinsics, but also objects being worn * and temporary spell effects. * * See also calc_mana() and calc_hitpoints(). * * Take note of the new "speed code", in particular, a very strong * player will start slowing down as soon as he reaches 150 pounds, * but not until he reaches 450 pounds will he be half as fast as * a normal kobold. This both hurts and helps the player, hurts * because in the old days a player could just avoid 300 pounds, * and helps because now carrying 300 pounds is not very painful. * * The "weapon" and "bow" do *not* add to the bonuses to hit or to * damage, since that would affect non-combat things. These values * are actually added in later, at the appropriate place. * * If id_only is true, calc_bonuses() will only use the known * information of objects; thus it returns what the player _knows_ * the character state to be. */ void calc_bonuses(object_type inventory[], player_state *state, bool id_only) { int i, j, hold; int extra_blows = 0; int extra_shots = 0; int extra_might = 0; object_type *o_ptr; bitflag f[OF_SIZE]; bitflag collect_f[OF_SIZE]; /*** Reset ***/ memset(state, 0, sizeof *state); /* Set various defaults */ state->speed = 110; state->num_blow = 1; /*** Extract race/class info ***/ /* Base infravision (purely racial) */ state->see_infra = rp_ptr->infra; /* Base skills */ for (i = 0; i < SKILL_MAX; i++) state->skills[i] = rp_ptr->r_skills[i] + cp_ptr->c_skills[i]; /*** Analyze player ***/ /* Extract the player flags */ player_flags(collect_f); /*** Analyze equipment ***/ /* Scan the equipment */ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) { o_ptr = &inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Extract the item flags */ if (id_only) object_flags_known(o_ptr, f); else object_flags(o_ptr, f); of_union(collect_f, f); /* Affect stats */ if (of_has(f, OF_STR)) state->stat_add[A_STR] += o_ptr->pval; if (of_has(f, OF_INT)) state->stat_add[A_INT] += o_ptr->pval; if (of_has(f, OF_WIS)) state->stat_add[A_WIS] += o_ptr->pval; if (of_has(f, OF_DEX)) state->stat_add[A_DEX] += o_ptr->pval; if (of_has(f, OF_CON)) state->stat_add[A_CON] += o_ptr->pval; if (of_has(f, OF_CHR)) state->stat_add[A_CHR] += o_ptr->pval; /* Affect stealth */ if (of_has(f, OF_STEALTH)) state->skills[SKILL_STEALTH] += o_ptr->pval; /* Affect searching ability (factor of five) */ if (of_has(f, OF_SEARCH)) state->skills[SKILL_SEARCH] += (o_ptr->pval * 5); /* Affect searching frequency (factor of five) */ if (of_has(f, OF_SEARCH)) state->skills[SKILL_SEARCH_FREQUENCY] += (o_ptr->pval * 5); /* Affect infravision */ if (of_has(f, OF_INFRA)) state->see_infra += o_ptr->pval; /* Affect digging (factor of 20) */ if (of_has(f, OF_TUNNEL)) state->skills[SKILL_DIGGING] += (o_ptr->pval * 20); /* Affect speed */ if (of_has(f, OF_SPEED)) state->speed += o_ptr->pval; /* Affect blows */ if (of_has(f, OF_BLOWS)) extra_blows += o_ptr->pval; /* Affect shots */ if (of_has(f, OF_SHOTS)) extra_shots += o_ptr->pval; /* Affect Might */ if (of_has(f, OF_MIGHT)) extra_might += o_ptr->pval; /* Modify the base armor class */ state->ac += o_ptr->ac; /* The base armor class is always known */ state->dis_ac += o_ptr->ac; /* Apply the bonuses to armor class */ if (!id_only || object_is_known(o_ptr)) state->to_a += o_ptr->to_a; /* Apply the mental bonuses to armor class, if known */ if (object_defence_plusses_are_visible(o_ptr)) state->dis_to_a += o_ptr->to_a; /* Hack -- do not apply "weapon" bonuses */ if (i == INVEN_WIELD) continue; /* Hack -- do not apply "bow" bonuses */ if (i == INVEN_BOW) continue; /* Apply the bonuses to hit/damage */ if (!id_only || object_is_known(o_ptr)) { state->to_h += o_ptr->to_h; state->to_d += o_ptr->to_d; } /* Apply the mental bonuses tp hit/damage, if known */ if (object_attack_plusses_are_visible(o_ptr)) { state->dis_to_h += o_ptr->to_h; state->dis_to_d += o_ptr->to_d; } } /*** Update all flags ***/ /* Good flags */ if (of_has(collect_f, OF_SLOW_DIGEST)) state->slow_digest = TRUE; if (of_has(collect_f, OF_FEATHER)) state->ffall = TRUE; if (of_has(collect_f, OF_REGEN)) state->regenerate = TRUE; if (of_has(collect_f, OF_TELEPATHY)) state->telepathy = TRUE; if (of_has(collect_f, OF_SEE_INVIS)) state->see_inv = TRUE; if (of_has(collect_f, OF_FREE_ACT)) state->free_act = TRUE; if (of_has(collect_f, OF_HOLD_LIFE)) state->hold_life = TRUE; /* Weird flags */ if (of_has(collect_f, OF_BLESSED)) state->bless_blade = TRUE; /* Bad flags */ if (of_has(collect_f, OF_IMPACT)) state->impact = TRUE; if (of_has(collect_f, OF_AGGRAVATE)) state->aggravate = TRUE; if (of_has(collect_f, OF_TELEPORT)) state->teleport = TRUE; if (of_has(collect_f, OF_DRAIN_EXP)) state->exp_drain = TRUE; if (of_has(collect_f, OF_IMPAIR_HP)) state->impair_hp = TRUE; if (of_has(collect_f, OF_IMPAIR_MANA)) state->impair_mana = TRUE; if (of_has(collect_f, OF_AFRAID)) state->afraid = TRUE; /* Vulnerability flags */ if (of_has(collect_f, OF_VULN_FIRE)) state->vuln_fire = TRUE; if (of_has(collect_f, OF_VULN_ACID)) state->vuln_acid = TRUE; if (of_has(collect_f, OF_VULN_COLD)) state->vuln_cold = TRUE; if (of_has(collect_f, OF_VULN_ELEC)) state->vuln_elec = TRUE; /* Immunity flags */ if (of_has(collect_f, OF_IM_FIRE)) state->immune_fire = TRUE; if (of_has(collect_f, OF_IM_ACID)) state->immune_acid = TRUE; if (of_has(collect_f, OF_IM_COLD)) state->immune_cold = TRUE; if (of_has(collect_f, OF_IM_ELEC)) state->immune_elec = TRUE; /* Resistance flags */ if (of_has(collect_f, OF_RES_ACID)) state->resist_acid = TRUE; if (of_has(collect_f, OF_RES_ELEC)) state->resist_elec = TRUE; if (of_has(collect_f, OF_RES_FIRE)) state->resist_fire = TRUE; if (of_has(collect_f, OF_RES_COLD)) state->resist_cold = TRUE; if (of_has(collect_f, OF_RES_POIS)) state->resist_pois = TRUE; if (of_has(collect_f, OF_RES_FEAR)) state->resist_fear = TRUE; if (of_has(collect_f, OF_RES_LIGHT)) state->resist_light = TRUE; if (of_has(collect_f, OF_RES_DARK)) state->resist_dark = TRUE; if (of_has(collect_f, OF_RES_BLIND)) state->resist_blind = TRUE; if (of_has(collect_f, OF_RES_CONFU)) state->resist_confu = TRUE; if (of_has(collect_f, OF_RES_SOUND)) state->resist_sound = TRUE; if (of_has(collect_f, OF_RES_SHARD)) state->resist_shard = TRUE; if (of_has(collect_f, OF_RES_NEXUS)) state->resist_nexus = TRUE; if (of_has(collect_f, OF_RES_NETHR)) state->resist_nethr = TRUE; if (of_has(collect_f, OF_RES_CHAOS)) state->resist_chaos = TRUE; if (of_has(collect_f, OF_RES_DISEN)) state->resist_disen = TRUE; /* Sustain flags */ if (of_has(collect_f, OF_SUST_STR)) state->sustain_str = TRUE; if (of_has(collect_f, OF_SUST_INT)) state->sustain_int = TRUE; if (of_has(collect_f, OF_SUST_WIS)) state->sustain_wis = TRUE; if (of_has(collect_f, OF_SUST_DEX)) state->sustain_dex = TRUE; if (of_has(collect_f, OF_SUST_CON)) state->sustain_con = TRUE; if (of_has(collect_f, OF_SUST_CHR)) state->sustain_chr = TRUE; /*** Handle stats ***/ /* Calculate stats */ for (i = 0; i < A_MAX; i++) { int add, top, use, ind; /* Extract modifier */ add = state->stat_add[i]; /* Maximize mode */ if (OPT(adult_maximize)) { /* Modify the stats for race/class */ add += (rp_ptr->r_adj[i] + cp_ptr->c_adj[i]); } /* Extract the new "stat_top" value for the stat */ top = modify_stat_value(p_ptr->stat_max[i], add); /* Save the new value */ state->stat_top[i] = top; /* Extract the new "stat_use" value for the stat */ use = modify_stat_value(p_ptr->stat_cur[i], add); /* Save the new value */ state->stat_use[i] = use; /* Values: n/a */ if (use <= 3) ind = 0; /* Values: 3, 4, ..., 18 */ else if (use <= 18) ind = (use - 3); /* Ranges: 18/00-18/09, ..., 18/210-18/219 */ else if (use <= 18+219) ind = (15 + (use - 18) / 10); /* Range: 18/220+ */ else ind = (37); assert((0 <= ind) && (ind < STAT_RANGE)); /* Save the new index */ state->stat_ind[i] = ind; } /*** Temporary flags ***/ /* Apply temporary "stun" */ if (p_ptr->timed[TMD_STUN] > 50) { state->to_h -= 20; state->dis_to_h -= 20; state->to_d -= 20; state->dis_to_d -= 20; state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 8 / 10; } else if (p_ptr->timed[TMD_STUN]) { state->to_h -= 5; state->dis_to_h -= 5; state->to_d -= 5; state->dis_to_d -= 5; state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 9 / 10; } /* Invulnerability */ if (p_ptr->timed[TMD_INVULN]) { state->to_a += 100; state->dis_to_a += 100; } /* Temporary blessing */ if (p_ptr->timed[TMD_BLESSED]) { state->to_a += 5; state->dis_to_a += 5; state->to_h += 10; state->dis_to_h += 10; state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 105 / 100; } /* Temporary shield */ if (p_ptr->timed[TMD_SHIELD]) { state->to_a += 50; state->dis_to_a += 50; } /* Temporary stoneskin */ if (p_ptr->timed[TMD_STONESKIN]) { state->to_a += 40; state->dis_to_a += 40; state->speed -= 5; } /* Temporary "Hero" */ if (p_ptr->timed[TMD_HERO]) { state->to_h += 12; state->dis_to_h += 12; state->resist_fear = TRUE; state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 105 / 100; } /* Temporary "Berserk" */ if (p_ptr->timed[TMD_SHERO]) { state->to_h += 24; state->dis_to_h += 24; state->to_a -= 10; state->dis_to_a -= 10; state->resist_fear = TRUE; state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 9 / 10; } /* Temporary "fast" */ if (p_ptr->timed[TMD_FAST] || p_ptr->timed[TMD_SPRINT]) state->speed += 10; /* Temporary "slow" */ if (p_ptr->timed[TMD_SLOW]) state->speed -= 10; /* Temporary see invisible */ if (p_ptr->timed[TMD_SINVIS]) state->see_inv = TRUE; /* Temporary infravision boost */ if (p_ptr->timed[TMD_SINFRA]) state->see_infra += 5; /* Temporary telepathy */ if (p_ptr->timed[TMD_TELEPATHY]) state->telepathy = TRUE; /* Temporary resist confusion */ if (p_ptr->timed[TMD_OPP_CONF]) state->resist_confu = TRUE; /* Fear */ if (p_ptr->timed[TMD_AFRAID] || p_ptr->timed[TMD_TERROR]) state->afraid = TRUE; if (p_ptr->timed[TMD_TERROR]) state->speed += 5; /* Fear can come from item flags too */ if (state->afraid) { state->to_h -= 20; state->dis_to_h -= 20; state->to_a += 8; state->dis_to_a += 8; state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 95 / 100; } /* Confusion */ if (p_ptr->timed[TMD_CONFUSED]) state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 75 / 100; /* Amnesia */ if (p_ptr->timed[TMD_AMNESIA]) state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 8 / 10; /* Poison */ if (p_ptr->timed[TMD_POISONED]) state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 95 / 100; /* Hallucination */ if (p_ptr->timed[TMD_IMAGE]) state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 8 / 10; /*** Analyze weight ***/ /* Extract the current weight (in tenth pounds) */ j = p_ptr->total_weight; /* Extract the "weight limit" (in tenth pounds) */ i = weight_limit(state); /* Apply "encumbrance" from weight */ if (j > i / 2) state->speed -= ((j - (i / 2)) / (i / 10)); /* Bloating slows the player down (a little) */ if (p_ptr->food >= PY_FOOD_MAX) state->speed -= 10; /* Searching slows the player down */ if (p_ptr->searching) state->speed -= 10; /* Sanity check on extreme speeds */ if (state->speed < 0) state->speed = 0; if (state->speed > 199) state->speed = 199; /*** Apply modifier bonuses ***/ /* Actual Modifier Bonuses (Un-inflate stat bonuses) */ state->to_a += ((int)(adj_dex_ta[state->stat_ind[A_DEX]]) - 128); state->to_d += ((int)(adj_str_td[state->stat_ind[A_STR]]) - 128); state->to_h += ((int)(adj_dex_th[state->stat_ind[A_DEX]]) - 128); state->to_h += ((int)(adj_str_th[state->stat_ind[A_STR]]) - 128); /* Displayed Modifier Bonuses (Un-inflate stat bonuses) */ state->dis_to_a += ((int)(adj_dex_ta[state->stat_ind[A_DEX]]) - 128); state->dis_to_d += ((int)(adj_str_td[state->stat_ind[A_STR]]) - 128); state->dis_to_h += ((int)(adj_dex_th[state->stat_ind[A_DEX]]) - 128); state->dis_to_h += ((int)(adj_str_th[state->stat_ind[A_STR]]) - 128); /*** Modify skills ***/ /* Affect Skill -- stealth (bonus one) */ state->skills[SKILL_STEALTH] += 1; /* Affect Skill -- disarming (DEX and INT) */ state->skills[SKILL_DISARM] += adj_dex_dis[state->stat_ind[A_DEX]]; state->skills[SKILL_DISARM] += adj_int_dis[state->stat_ind[A_INT]]; /* Affect Skill -- magic devices (INT) */ state->skills[SKILL_DEVICE] += adj_int_dev[state->stat_ind[A_INT]]; /* Affect Skill -- saving throw (WIS) */ state->skills[SKILL_SAVE] += adj_wis_sav[state->stat_ind[A_WIS]]; /* Affect Skill -- digging (STR) */ state->skills[SKILL_DIGGING] += adj_str_dig[state->stat_ind[A_STR]]; /* Affect Skills (Level, by Class) */ for (i = 0; i < SKILL_MAX; i++) state->skills[i] += (cp_ptr->x_skills[i] * p_ptr->lev / 10); /* Limit Skill -- digging from 1 up */ if (state->skills[SKILL_DIGGING] < 1) state->skills[SKILL_DIGGING] = 1; /* Limit Skill -- stealth from 0 to 30 */ if (state->skills[SKILL_STEALTH] > 30) state->skills[SKILL_STEALTH] = 30; if (state->skills[SKILL_STEALTH] < 0) state->skills[SKILL_STEALTH] = 0; /* Apply Skill -- Extract noise from stealth */ state->noise = (1L << (30 - state->skills[SKILL_STEALTH])); /* Obtain the "hold" value */ hold = adj_str_hold[state->stat_ind[A_STR]]; /*** Analyze current bow ***/ /* Examine the "current bow" */ o_ptr = &inventory[INVEN_BOW]; /* Assume not heavy */ state->heavy_shoot = FALSE; /* It is hard to carholdry a heavy bow */ if (hold < o_ptr->weight / 10) { /* Hard to wield a heavy bow */ state->to_h += 2 * (hold - o_ptr->weight / 10); state->dis_to_h += 2 * (hold - o_ptr->weight / 10); /* Heavy Bow */ state->heavy_shoot = TRUE; } /* Analyze launcher */ if (o_ptr->k_idx) { /* Get to shoot */ state->num_fire = 1; /* Analyze the launcher */ switch (o_ptr->sval) { /* Sling and ammo */ case SV_SLING: { state->ammo_tval = TV_SHOT; state->ammo_mult = 2; break; } /* Short Bow and Arrow */ case SV_SHORT_BOW: { state->ammo_tval = TV_ARROW; state->ammo_mult = 2; break; } /* Long Bow and Arrow */ case SV_LONG_BOW: { state->ammo_tval = TV_ARROW; state->ammo_mult = 3; break; } /* Light Crossbow and Bolt */ case SV_LIGHT_XBOW: { state->ammo_tval = TV_BOLT; state->ammo_mult = 3; break; } /* Heavy Crossbow and Bolt */ case SV_HEAVY_XBOW: { state->ammo_tval = TV_BOLT; state->ammo_mult = 4; break; } } /* Apply special flags */ if (o_ptr->k_idx && !state->heavy_shoot) { /* Extra shots */ state->num_fire += extra_shots; /* Extra might */ state->ammo_mult += extra_might; /* Hack -- Rangers love Bows */ if (player_has(PF_EXTRA_SHOT) && (state->ammo_tval == TV_ARROW)) { /* Extra shot at level 20 */ if (p_ptr->lev >= 20) state->num_fire++; /* Extra shot at level 40 */ if (p_ptr->lev >= 40) state->num_fire++; } } /* Require at least one shot */ if (state->num_fire < 1) state->num_fire = 1; } /*** Analyze weapon ***/ /* Examine the "current weapon" */ o_ptr = &inventory[INVEN_WIELD]; /* Assume not heavy */ state->heavy_wield = FALSE; /* It is hard to hold a heavy weapon */ if (hold < o_ptr->weight / 10) { /* Hard to wield a heavy weapon */ state->to_h += 2 * (hold - o_ptr->weight / 10); state->dis_to_h += 2 * (hold - o_ptr->weight / 10); /* Heavy weapon */ state->heavy_wield = TRUE; } /* Non-object means barehanded attacks */ if (!o_ptr->k_idx) assert(o_ptr->weight == 0); /* Normal weapons */ if (!state->heavy_wield) { /* Calculate number of blows */ state->num_blow = calc_blows(o_ptr, state) + extra_blows; /* Boost digging skill by weapon weight */ state->skills[SKILL_DIGGING] += (o_ptr->weight / 10); } /* Assume okay */ state->icky_wield = FALSE; /* Priest weapon penalty for non-blessed edged weapons */ if (player_has(PF_BLESS_WEAPON) && (!state->bless_blade) && ((o_ptr->tval == TV_SWORD) || (o_ptr->tval == TV_POLEARM))) { /* Reduce the real bonuses */ state->to_h -= 2; state->to_d -= 2; /* Reduce the mental bonuses */ state->dis_to_h -= 2; state->dis_to_d -= 2; /* Icky weapon */ state->icky_wield = TRUE; } return; }
/** * Allow one item to "absorb" another, assuming they are similar. * * The blending of the "note" field assumes that either (1) one has an * inscription and the other does not, or (2) neither has an inscription. * In both these cases, we can simply use the existing note, unless the * blending object has a note, in which case we use that note. * * These assumptions are enforced by the "object_similar()" code. */ static void object_absorb_merge(struct object *obj1, const struct object *obj2) { int total; /* First object gains any extra knowledge from second */ if (obj1->known && obj2->known) { of_union(obj1->known->flags, obj2->known->flags); if (obj2->known->ego) obj1->known->ego = (struct ego_item *)1; obj1->known->pval |= obj2->known->pval; obj1->known->dd |= obj2->known->dd; obj1->known->ds |= obj2->known->ds; obj1->known->ac |= obj2->known->ac; obj1->known->to_a |= obj2->known->to_a; obj1->known->to_h |= obj2->known->to_h; obj1->known->to_d |= obj2->known->to_d; if (obj2->known->effect) obj1->known->effect = (struct effect *)1; } /* Merge inscriptions */ if (obj2->note) obj1->note = obj2->note; /* Combine timeouts for rod stacking */ if (tval_can_have_timeout(obj1)) obj1->timeout += obj2->timeout; /* Combine pvals for wands and staves */ if (tval_can_have_charges(obj1) || tval_is_money(obj1)) { total = obj1->pval + obj2->pval; obj1->pval = total >= MAX_PVAL ? MAX_PVAL : total; } /* Combine origin data as best we can */ if (obj1->origin != obj2->origin || obj1->origin_depth != obj2->origin_depth || obj1->origin_xtra != obj2->origin_xtra) { int act = 2; if (obj1->origin_xtra && obj2->origin_xtra) { struct monster_race *race1 = &r_info[obj1->origin_xtra]; struct monster_race *race2 = &r_info[obj2->origin_xtra]; bool r1_uniq = rf_has(race1->flags, RF_UNIQUE) ? true : false; bool r2_uniq = rf_has(race2->flags, RF_UNIQUE) ? true : false; if (r1_uniq && !r2_uniq) act = 0; else if (r2_uniq && !r1_uniq) act = 1; else act = 2; } switch (act) { /* Overwrite with obj2 */ case 1: { obj1->origin = obj2->origin; obj1->origin_depth = obj2->origin_depth; obj1->origin_xtra = obj2->origin_xtra; } /* Set as "mixed" */ case 2: { obj1->origin = ORIGIN_MIXED; } } } }