Beispiel #1
0
/**
 * \returns whether the object's pval is known to the player
 */
bool object_pval_is_visible(const object_type *o_ptr)
{
	bitflag f[OF_SIZE];

	if (o_ptr->ident & IDENT_STORE)
		return TRUE;

	/* Aware jewelry with non-variable pvals */
	if (object_is_jewelry(o_ptr) && object_flavor_is_aware(o_ptr))
	{
		const object_kind *k_ptr = &k_info[o_ptr->k_idx];

		if (!randcalc_varies(k_ptr->pval))
			return TRUE;
	}

	if (object_was_worn(o_ptr))
	{
		object_flags_known(o_ptr, f);

		if (flags_test(f, OF_SIZE, OF_PVAL_MASK, FLAG_END))
			return TRUE;
	}

	return FALSE;
}
Beispiel #2
0
static size_t obj_desc_inscrip(const object_type *o_ptr, char *buf, size_t max, size_t end)
{
	const char *u[4] = { 0, 0, 0, 0 };
	int n = 0;
	int feel = object_pseudo(o_ptr);
	bitflag flags_known[OF_SIZE];

	object_flags_known(o_ptr, flags_known);

	/* Get inscription */
	if (o_ptr->note)
		u[n++] = quark_str(o_ptr->note);

	/* Use special inscription, if any */
	if (!object_is_known(o_ptr) && feel)
	{
		/* cannot tell excellent vs strange vs splendid until wield */
		if (!object_was_worn(o_ptr) && ego_item_p(o_ptr))
			u[n++] = "ego";
		else
			u[n++] = inscrip_text[feel];
	}
	else if ((o_ptr->ident & IDENT_EMPTY) && !object_is_known(o_ptr))
		u[n++] = "empty";
	else if (!object_is_known(o_ptr) && object_was_worn(o_ptr))
	{
		if (wield_slot(o_ptr) == INVEN_WIELD || wield_slot(o_ptr) == INVEN_BOW)
			u[n++] = "wielded";
		else u[n++] = "worn";
	}
	else if (!object_is_known(o_ptr) && object_was_fired(o_ptr))
		u[n++] = "fired";
	else if (!object_flavor_is_aware(o_ptr) && object_flavor_was_tried(o_ptr))
		u[n++] = "tried";

	/* Note curses */
	if (flags_test(flags_known, OF_SIZE, OF_CURSE_MASK, FLAG_END))
		u[n++] = "cursed";

	/* Note squelch */
	if (squelch_item_ok(o_ptr))
		u[n++] = "squelch";

	if (n)
	{
		int i;
		for (i = 0; i < n; i++)
		{
			if (i == 0)
				strnfcat(buf, max, &end, " {");
			strnfcat(buf, max, &end, "%s", u[i]);
			if (i < n-1)
				strnfcat(buf, max, &end, ", ");
		}

		strnfcat(buf, max, &end, "}");
	}

	return end;
}
Beispiel #3
0
/*
 * Choose the best direction for "flowing".
 *
 * Note that ghosts and rock-eaters generally don't flow because they can move
 * through obstacles.
 *
 * Monsters first try to use up-to-date distance information ('sound') as
 * saved in cave->squares[y][x].cost.  Failing that, they'll try using scent
 * ('when') which is just old cost information.
 *
 * Tracking by 'scent' means that monsters end up near enough the player to
 * switch to 'sound' (cost), or they end up somewhere the player left via 
 * teleport.  Teleporting away from a location will cause the monsters who
 * were chasing the player to converge on that location as long as the player
 * is still near enough to "annoy" them without being close enough to chase
 * directly.
 */
static bool get_moves_flow(struct chunk *c, struct monster *m_ptr)
{
	int i;

	int best_when = 0;
	int best_cost = 999;
	int best_direction = 0;

	int py = player->py, px = player->px;
	int my = m_ptr->fy, mx = m_ptr->fx;

	/* Only use this algorithm for passwall monsters if near permanent walls,
	 * to avoid getting snagged */
	if (flags_test(m_ptr->race->flags, RF_SIZE, RF_PASS_WALL, RF_KILL_WALL,
				   FLAG_END) && !near_permwall(m_ptr, c))
		return (FALSE);

	/* If the player has never been near this grid, abort */
	if (c->squares[my][mx].when == 0) return FALSE;

	/* Monster is too far away to notice the player */
	if (c->squares[my][mx].cost > z_info->max_flow_depth) return FALSE;
	if (c->squares[my][mx].cost > m_ptr->race->aaf) return FALSE;

	/* If the player can see monster, run towards them */
	if (player_has_los_bold(my, mx)) return FALSE;

	/* Check nearby grids, diagonals first */
	/* This gives preference to the cardinal directions */
	for (i = 7; i >= 0; i--)
	{
		/* Get the location */
		int y = my + ddy_ddd[i];
		int x = mx + ddx_ddd[i];

		/* Ignore unvisited/unpassable locations */
		if (c->squares[y][x].when == 0) continue;

		/* Ignore locations whose data is more stale */
		if (c->squares[y][x].when < best_when) continue;

		/* Ignore locations which are farther away */
		if (c->squares[y][x].cost > best_cost) continue;

		/* Save the cost and time */
		best_when = c->squares[y][x].when;
		best_cost = c->squares[y][x].cost;
		best_direction = i;
	}

	/* Save the location to flow toward */
 	/* We multiply by 16 to angle slightly toward the player's actual location */
	if (best_direction) {
		m_ptr->ty = py + 16 * ddy_ddd[best_direction];
		m_ptr->tx = px + 16 * ddx_ddd[best_direction];
		return TRUE;
	}

	return FALSE;
}
Beispiel #4
0
static size_t obj_desc_pval(const object_type *o_ptr, char *buf, size_t max, size_t end)
{
	bitflag f[OF_SIZE];

	object_flags(o_ptr, f);

	if (!flags_test(f, OF_SIZE, OF_PVAL_MASK, FLAG_END)) return end;

	strnfcat(buf, max, &end, " (%+d", o_ptr->pval);

	if (!of_has(f, OF_HIDE_TYPE))
	{
		if (of_has(f, OF_STEALTH))
			strnfcat(buf, max, &end, " stealth");
		else if (of_has(f, OF_SEARCH))
			strnfcat(buf, max, &end, " searching");
		else if (of_has(f, OF_INFRA))
			strnfcat(buf, max, &end, " infravision");
		else if (of_has(f, OF_SPEED))
			strnfcat(buf, max, &end, " speed");
		else if (of_has(f, OF_BLOWS))
			strnfcat(buf, max, &end, " attack%s", PLURAL(o_ptr->pval));
	}

	strnfcat(buf, max, &end, ")");

	return end;
}
Beispiel #5
0
void search_cycle(CA *ca, char *graph, UINT starting_state)
{
  UINT actual_state = starting_state;
  int is_new_cycle = 0;

  while (!flags_test(graph, actual_state, STATE_HAS_BEEN_VISITED))
  {
    flags_set(graph, actual_state, STATE_HAS_BEEN_VISITED | STATE_IS_BEING_VISITED);
    actual_state = next_state(ca, actual_state);
  }

  is_new_cycle = flags_test(graph, actual_state, STATE_IS_BEING_VISITED);

  if (is_new_cycle)
  {
    UINT cycle_len = 0;

    while (flags_test(graph, actual_state, STATE_IS_BEING_VISITED))
    {
      flags_unset(graph, actual_state, STATE_IS_BEING_VISITED);

      actual_state = next_state(ca, actual_state);

      cycle_len ++;
    }

    /* printf("len %u seed %u start %u ", cycle_len, actual_state, starting_state); */
    printf("%" UFM  "\n", cycle_len);
    fflush(stdout);
  }

  for  (actual_state = starting_state;
        flags_test(graph, actual_state, STATE_IS_BEING_VISITED);
        actual_state = next_state(ca, actual_state))
  {
     flags_unset(graph, actual_state, STATE_IS_BEING_VISITED);
  }
}
Beispiel #6
0
/*
 * \returns whether it is possible an object has a high resist given the
 *          player's current knowledge
 */
bool object_high_resist_is_possible(const object_type *o_ptr)
{
	bitflag flags[OF_SIZE];

	/* Actual object flags */
	object_flags(o_ptr, flags);

	/* Add player's uncertainty */
	of_comp_union(flags, o_ptr->known_flags);

	/* Check for possible high resist */
	if (flags_test(flags, OF_SIZE, OF_HIGH_RESIST_MASK, FLAG_END))
		return TRUE;
	else
		return FALSE;
}
Beispiel #7
0
int
main(int argc, char *argv[])
{
  UINT i;

  unsigned int N;
  UINT NSTATES;

  unsigned int rule;
  CA *ca;

  char *graph;

  if (argc != 3)
  {
    fprintf(stderr, "usage: %s rule ca-size\n", PROGRAM_NAME);
    exit(EXIT_FAILURE);
  }

  sscanf(argv[1], "%u", &rule);

  sscanf(argv[2], "%u", &N);

  if (DEBUG)
    fprintf(stderr, "rule %u\nN=%u\n", rule, N);

  ca = ca_create(N, rule);

  NSTATES =  2;
  NSTATES <<= (N - 1);

  graph = create_graph(NSTATES);

  for (i = 0; i < NSTATES; ++i)
    flags_unset(graph, i, STATE_ALL_SET_MASK);

  for (i = 0; i < NSTATES; ++i)
    if (!flags_test(graph, i, STATE_HAS_BEEN_VISITED))
      search_cycle(ca, graph, i);

  free_graph(graph);
  ca_destroy(ca);

  return EXIT_SUCCESS;
}
Beispiel #8
0
/**
 * Calculate minimum and desired combat ranges.  -BR-
 */
static void find_range(struct monster *mon)
{
	u16b p_lev, m_lev;
	u16b p_chp, p_mhp;
	u16b m_chp, m_mhp;
	u32b p_val, m_val;

	/* Monsters will run up to z_info->flee_range grids out of sight */
	int flee_range = z_info->max_sight + z_info->flee_range;

	/* All "afraid" monsters will run away */
	if (mon->m_timed[MON_TMD_FEAR])
		mon->min_range = flee_range;

	else {

		/* Minimum distance - stay at least this far if possible */
		mon->min_range = 1;

		/* Examine player power (level) */
		p_lev = player->lev;

		/* Hack - increase p_lev based on specialty abilities */

		/* Examine monster power (level plus morale) */
		m_lev = mon->race->level + (mon->midx & 0x08) + 25;

		/* Simple cases first */
		if (m_lev + 3 < p_lev)
			mon->min_range = flee_range;
		else if (m_lev - 5 < p_lev) {

			/* Examine player health */
			p_chp = player->chp;
			p_mhp = player->mhp;

			/* Examine monster health */
			m_chp = mon->hp;
			m_mhp = mon->maxhp;

			/* Prepare to optimize the calculation */
			p_val = (p_lev * p_mhp) + (p_chp << 2);	/* div p_mhp */
			m_val = (m_lev * m_mhp) + (m_chp << 2);	/* div m_mhp */

			/* Strong players scare strong monsters */
			if (p_val * m_mhp > m_val * p_mhp)
				mon->min_range = flee_range;
		}
	}

	if (mon->min_range < flee_range) {
		/* Creatures that don't move never like to get too close */
		if (rf_has(mon->race->flags, RF_NEVER_MOVE))
			mon->min_range += 3;

		/* Spellcasters that don't strike never like to get too close */
		if (rf_has(mon->race->flags, RF_NEVER_BLOW))
			mon->min_range += 3;
	}

	/* Maximum range to flee to */
	if (!(mon->min_range < flee_range))
		mon->min_range = flee_range;

	/* Nearby monsters won't run away */
	else if (mon->cdis < z_info->turn_range)
		mon->min_range = 1;

	/* Now find preferred range */
	mon->best_range = mon->min_range;

	/* Archers are quite happy at a good distance */
	//if (rf_has(mon->race->flags, RF_ARCHER))
	//	mon->best_range += 3;

	if (mon->race->freq_spell > 24) {
		/* Breathers like point blank range */
		if (flags_test(mon->race->spell_flags, RSF_SIZE, RSF_BREATH_MASK,
					   FLAG_END)
			&& (mon->best_range < 6) && (mon->hp > mon->maxhp / 2))
			mon->best_range = 6;

		/* Other spell casters will sit back and cast */
		else
			mon->best_range += 3;
	}
}
Beispiel #9
0
/**
 * Choose "logical" directions for monster movement
 */
static bool get_moves(struct chunk *c, struct monster *mon, int *dir)
{
	int py = player->py;
	int px = player->px;

	int y, x;

	/* Monsters will run up to z_info->flee_range grids out of sight */
	int flee_range = z_info->max_sight + z_info->flee_range;

	bool done = false;

	/* Calculate range */
	find_range(mon);

	/* Flow towards the player */
	if (get_moves_flow(c, mon)) {
		/* Extract the "pseudo-direction" */
		y = mon->ty - mon->fy;
		x = mon->tx - mon->fx;
	} else {
		/* Head straight for the player */
		y = player->py - mon->fy;
		x = player->px - mon->fx;
	}

	/* Normal animal packs try to get the player out of corridors. */
	if (rf_has(mon->race->flags, RF_GROUP_AI) &&
	    !flags_test(mon->race->flags, RF_SIZE, RF_PASS_WALL, RF_KILL_WALL,
					FLAG_END)) {
		int i, open = 0;

		/* Count empty grids next to player */
		for (i = 0; i < 8; i++) {
			int ry = py + ddy_ddd[i];
			int rx = px + ddx_ddd[i];
			/* Check grid around the player for room interior (room walls count)
			 * or other empty space */
			if (square_ispassable(c, ry, rx) || square_isroom(c, ry, rx)) {
				/* One more open grid */
				open++;
			}
		}

		/* Not in an empty space and strong player */
		if ((open < 7) && (player->chp > player->mhp / 2)) {
			/* Find hiding place */
			if (find_hiding(c, mon)) {
				done = true;
				y = mon->ty - mon->fy;
				x = mon->tx - mon->fx;
			}
		}
	}

	/* Apply fear */
	if (!done && (mon->min_range == flee_range)) {
		/* Try to find safe place */
		if (!find_safety(c, mon)) {
			/* Just leg it away from the player */
			y = (-y);
			x = (-x);
		} else {
			/* Set a course for the safe place */
			get_moves_fear(c, mon);
			y = mon->ty - mon->fy;
			x = mon->tx - mon->fx;
		}

		done = true;
	}

	/* Monster groups try to surround the player */
	if (!done && rf_has(mon->race->flags, RF_GROUP_AI)) {
		int i, yy = mon->ty, xx = mon->tx;

		/* If we are not already adjacent */
		if (mon->cdis > 1) {
			/* Find an empty square near the player to fill */
			int tmp = randint0(8);
			for (i = 0; i < 8; i++) {
				/* Pick squares near player (pseudo-randomly) */
				yy = py + ddy_ddd[(tmp + i) & 7];
				xx = px + ddx_ddd[(tmp + i) & 7];

				/* Ignore filled grids */
				if (!square_isempty(cave, yy, xx)) continue;

				/* Try to fill this hole */
				break;
			}
		}

		/* Extract the new "pseudo-direction" */
		y = yy - mon->fy;
		x = xx - mon->fx;
	}

	/* Check for no move */
	if (!x && !y) return (false);

	/* Pick the correct direction */
	*dir = choose_direction(y, x);

	/* Want to move */
	return (true);
}
Beispiel #10
0
/**
 * Choose the best direction for "flowing".
 *
 * Note that ghosts and rock-eaters generally don't flow because they can move
 * through obstacles.
 *
 * Monsters first try to use up-to-date distance information ('sound') as
 * saved in cave->squares[y][x].noise.  Failing that, they'll try using scent
 * ('scent') which is just old noise information.
 *
 * Tracking by 'scent' means that monsters end up near enough the player to
 * switch to 'sound' (noise), or they end up somewhere the player left via 
 * teleport.  Teleporting away from a location will cause the monsters who
 * were chasing the player to converge on that location as long as the player
 * is still near enough to "annoy" them without being close enough to chase
 * directly.
 */
static bool get_moves_flow(struct chunk *c, struct monster *mon)
{
	int i;

	int best_scent = 0;
	int best_noise = 999;
	int best_direction = 0;
	bool found_direction = false;

	int py = player->py, px = player->px;
	int my = mon->fy, mx = mon->fx;

	/* Only use this algorithm for passwall monsters if near permanent walls,
	 * to avoid getting snagged */
	if (flags_test(mon->race->flags, RF_SIZE, RF_PASS_WALL, RF_KILL_WALL,
				   FLAG_END) && !near_permwall(mon, c))
		return (false);

	/* The player is not currently near the monster grid */
	if (c->squares[my][mx].scent < c->squares[py][px].scent)
		/* If the player has never been near this grid, abort */
		if (c->squares[my][mx].scent == 0) return false;

	/* Monster is too far away to notice the player */
	if (c->squares[my][mx].noise > z_info->max_flow_depth) return false;
	if (c->squares[my][mx].noise > mon->race->aaf) return false;

	/* If the player can see monster, set target and run towards them */
	if (square_isview(c, my, mx)) {
		mon->ty = player->py;
		mon->tx = player->px;
		return false;
	}

	/* Check nearby grids, diagonals first */
	/* This gives preference to the cardinal directions */
	for (i = 7; i >= 0; i--) {
		/* Get the location */
		int y = my + ddy_ddd[i];
		int x = mx + ddx_ddd[i];

		/* Bounds check */
		if (!square_in_bounds(c, y, x)) continue;

		/* Ignore unvisited/unpassable locations */
		if (c->squares[y][x].scent == 0) continue;

		/* Ignore locations whose data is more stale */
		if (c->squares[y][x].scent < best_scent) continue;

		/* Ignore locations which are farther away */
		if (c->squares[y][x].noise > best_noise) continue;

		/* Ignore lava if they can't handle the heat */
		if (square_isfiery(c, y, x) && !rf_has(mon->race->flags, RF_IM_FIRE))
			continue;

		/* Save the noise and time */
		best_scent = c->squares[y][x].scent;
		best_noise = c->squares[y][x].noise;
		best_direction = i;
		found_direction = true;
	}

	/* Save the location to flow toward */
	/* Multiply by 16 to angle slightly toward the player's actual location */
	if (found_direction) {
		int dy = 0, dx = 0;

		/* Ridiculous - actually multiply by whatever doesn't underflow the 
		 * byte for ty and tx.  Really should do a better solution - NRM */
		for (i = 0; i < 16; i++)
			if ((py + dy > 0) && (px + dx > 0)) {
				dy += ddy_ddd[best_direction];
				dx += ddx_ddd[best_direction];
			}

		mon->ty = py + dy;
		mon->tx = px + dx;
		return true;
	}

	return false;
}
Beispiel #11
0
/**
 * This function takes a pointer to a grid info struct describing the 
 * contents of a grid location (as obtained through the function map_info)
 * and fills in the character and attr pairs for display.
 *
 * ap and cp are filled with the attr/char pair for the monster, object or 
 * floor tile that is at the "top" of the grid (monsters covering objects, 
 * which cover floor, assuming all are present).
 *
 * tap and tcp are filled with the attr/char pair for the floor, regardless
 * of what is on it.  This can be used by graphical displays with
 * transparency to place an object onto a floor tile, is desired.
 *
 * Any lighting effects are also applied to these pairs, clear monsters allow
 * the underlying colour or feature to show through (ATTR_CLEAR and
 * CHAR_CLEAR), multi-hued colour-changing (ATTR_MULTI) is applied, and so on.
 * Technically, the flag "CHAR_MULTI" is supposed to indicate that a monster 
 * looks strange when examined, but this flag is currently ignored.
 *
 * NOTES:
 * This is called pretty frequently, whenever a grid on the map display
 * needs updating, so don't overcomplicate it.
 *
 * The "zero" entry in the feature/object/monster arrays are
 * used to provide "special" attr/char codes, with "monster zero" being
 * used for the player attr/char, "object zero" being used for the "pile"
 * attr/char, and "feature zero" being used for the "darkness" attr/char.
 *
 * TODO:
 * The transformations for tile colors, or brightness for the 16x16
 * tiles should be handled differently.  One possibility would be to
 * extend feature_type with attr/char definitions for the different states.
 * This will probably be done outside of the current text->graphics mappings
 * though.
 */
void grid_data_as_text(struct grid_data *g, int *ap, wchar_t *cp, int *tap,
					   wchar_t *tcp)
{
	struct feature *feat = &f_info[g->f_idx];

	int a = feat_x_attr[g->lighting][feat->fidx];
	wchar_t c = feat_x_char[g->lighting][feat->fidx];
	bool skip_objects = false;

	/* Get the colour for ASCII */
	if (use_graphics == GRAPHICS_NONE)
		grid_get_attr(g, &a);

	/* Save the terrain info for the transparency effects */
	(*tap) = a;
	(*tcp) = c;

	/* There is a trap in this grid, and we are not hallucinating */
	if (g->trap && (!g->hallucinate)) {
	    /* Change graphics to indicate visible traps, skip objects if a web */
	    skip_objects = get_trap_graphics(cave, g, &a, &c);
	}

	if (!skip_objects) {
		/* If there's an object, deal with that. */
		if (g->unseen_money) {

			/* $$$ gets an orange star*/
			a = object_kind_attr(unknown_gold_kind);
			c = object_kind_char(unknown_gold_kind);

		} else if (g->unseen_object) {

			/* Everything else gets a red star */
			a = object_kind_attr(unknown_item_kind);
			c = object_kind_char(unknown_item_kind);

		} else if (g->first_kind) {
			if (g->hallucinate) {
				/* Just pick a random object to display. */
				hallucinatory_object(&a, &c);
			} else if (g->multiple_objects) {
				/* Get the "pile" feature instead */
				a = object_kind_attr(pile_kind);
				c = object_kind_char(pile_kind);
			} else {
				/* Normal attr and char */
				a = object_kind_attr(g->first_kind);
				c = object_kind_char(g->first_kind);
			}
		}
	}

	/* Handle monsters, the player and trap borders */
	if (g->m_idx > 0) {
		if (g->hallucinate) {
			/* Just pick a random monster to display. */
			hallucinatory_monster(&a, &c);
		} else if (!monster_is_mimicking(cave_monster(cave, g->m_idx)))	{
			struct monster *mon = cave_monster(cave, g->m_idx);

			byte da;
			wchar_t dc;

			/* Desired attr & char */
			da = monster_x_attr[mon->race->ridx];
			dc = monster_x_char[mon->race->ridx];

			/* Special handling of attrs and/or chars */
			if (da & 0x80) {
				/* Special attr/char codes */
				a = da;
				c = dc;
			} else if (OPT(player, purple_uniques) && 
					   rf_has(mon->race->flags, RF_UNIQUE)) {
				/* Turn uniques purple if desired (violet, actually) */
				a = COLOUR_VIOLET;
				c = dc;
			} else if (rf_has(mon->race->flags, RF_ATTR_MULTI) ||
					   rf_has(mon->race->flags, RF_ATTR_FLICKER) ||
					   rf_has(mon->race->flags, RF_ATTR_RAND)) {
				/* Multi-hued monster */
				a = mon->attr ? mon->attr : da;
				c = dc;
			} else if (!flags_test(mon->race->flags, RF_SIZE,
								   RF_ATTR_CLEAR, RF_CHAR_CLEAR, FLAG_END)) {
				/* Normal monster (not "clear" in any way) */
				a = da;
				/* Desired attr & char. da is not used, should a be set to it?*/
				/*da = monster_x_attr[mon->race->ridx];*/
				dc = monster_x_char[mon->race->ridx];
				c = dc;
			} else if (a & 0x80) {
				/* Hack -- Bizarre grid under monster */
				a = da;
				c = dc;
			} else if (!rf_has(mon->race->flags, RF_CHAR_CLEAR)) {
				/* Normal char, Clear attr, monster */
				c = dc;
			} else if (!rf_has(mon->race->flags, RF_ATTR_CLEAR)) {
				/* Normal attr, Clear char, monster */
				a = da;
			}

			/* Store the drawing attr so we can use it elsewhere */
			mon->attr = a;
		}
	} else if (g->is_player) {
		struct monster_race *race = &r_info[0];

		/* Get the "player" attr */
		a = monster_x_attr[race->ridx];
		if ((OPT(player, hp_changes_color)) && !(a & 0x80)) {
			switch(player->chp * 10 / player->mhp)
			{
			case 10:
			case  9: 
			{
				a = COLOUR_WHITE; 
				break;
			}
			case  8:
			case  7:
			{
				a = COLOUR_YELLOW;
				break;
			}
			case  6:
			case  5:
			{
				a = COLOUR_ORANGE;
				break;
			}
			case  4:
			case  3:
			{
				a = COLOUR_L_RED;
				break;
			}
			case  2:
			case  1:
			case  0:
			{
				a = COLOUR_RED;
				break;
			}
			default:
			{
				a = COLOUR_WHITE;
				break;
			}
			}
		}

		/* Get the "player" char */
		c = monster_x_char[race->ridx];
	}

	/* Result */
	(*ap) = a;
	(*cp) = c;
}
Beispiel #12
0
/*
 * Given an object, return a short identifier which gives some idea of what
 * the item is.
 */
obj_pseudo_t object_pseudo(const object_type *o_ptr)
{
	object_kind *k_ptr = &k_info[o_ptr->k_idx];
	bitflag flags[OF_SIZE];

	/* Get the known and obvious flags on the object,
	 * not including curses or properties of the kind
	 */
	object_flags_known(o_ptr, flags);

	/* MEGA-hack : there needs to be a table of what is obvious in each slot perhaps for each class */
	/* FA on gloves is obvious to mage casters */
	if (object_FA_would_be_obvious(o_ptr))
		flags_mask(flags, OF_SIZE, OF_OBVIOUS_MASK, OF_FREE_ACT, FLAG_END);
	else
		flags_mask(flags, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END);

	flags_clear(flags, OF_SIZE, OF_CURSE_MASK, FLAG_END);
	of_diff(flags, k_ptr->flags);

	if (o_ptr->ident & IDENT_INDESTRUCT)
		return INSCRIP_SPECIAL;
	if ((object_was_sensed(o_ptr) || object_was_worn(o_ptr)) && artifact_p(o_ptr))
		return INSCRIP_SPECIAL;

	/* jewelry does not pseudo */
	if (object_is_jewelry(o_ptr))
		return INSCRIP_NULL;

	/* XXX Eddie should also check for flags with pvals where the pval exceeds
	 * the base pval for things like picks of digging, though for now acid brand gets those
	 */
	if (!of_is_empty(flags))
		return INSCRIP_SPLENDID;

	if (!object_is_known(o_ptr) && !object_was_sensed(o_ptr))
		return INSCRIP_NULL;

	if (ego_item_p(o_ptr))
	{
		/* uncursed bad egos are not excellent */
		if (flags_test(e_info[o_ptr->name2].flags, OF_SIZE, OF_CURSE_MASK, FLAG_END))
			return INSCRIP_STRANGE; /* XXX Eddie need something worse */
		else
			return INSCRIP_EXCELLENT;
	}

	if (o_ptr->to_a == randcalc(k_ptr->to_a, 0, MINIMISE) &&
	    o_ptr->to_h == randcalc(k_ptr->to_h, 0, MINIMISE) &&
		 o_ptr->to_d == randcalc(k_ptr->to_d, 0, MINIMISE))
		return INSCRIP_AVERAGE;

	if (o_ptr->to_a >= randcalc(k_ptr->to_a, 0, MINIMISE) &&
	    o_ptr->to_h >= randcalc(k_ptr->to_h, 0, MINIMISE) &&
	    o_ptr->to_d >= randcalc(k_ptr->to_d, 0, MINIMISE))
		return INSCRIP_MAGICAL;

	if (o_ptr->to_a <= randcalc(k_ptr->to_a, 0, MINIMISE) &&
	    o_ptr->to_h <= randcalc(k_ptr->to_h, 0, MINIMISE) &&
	    o_ptr->to_d <= randcalc(k_ptr->to_d, 0, MINIMISE))
		return INSCRIP_MAGICAL;

	return INSCRIP_STRANGE;
}
Beispiel #13
0
/**
 * Evaluate the whole monster list and write a new one.  power and scaled_power
 * are always adjusted, level, rarity and mexp only if requested.
 */
errr eval_monster_power(struct monster_race *racelist)
{
	int i, j, iteration;
	byte lvl;
	struct monster_race *race = NULL;
	ang_file *mon_fp;
	char buf[1024];
	bool dump = FALSE;
	bool wrote = TRUE;

	/* Allocate arrays */
	power = mem_zalloc(z_info->r_max * sizeof(long));
	scaled_power = mem_zalloc(z_info->r_max * sizeof(long));
	final_hp = mem_zalloc(z_info->r_max * sizeof(long));
	final_melee_dam = mem_zalloc(z_info->r_max * sizeof(long));
	final_spell_dam = mem_zalloc(z_info->r_max * sizeof(long));
	highest_threat = mem_zalloc(z_info->r_max * sizeof(int));

	for (iteration = 0; iteration < 3; iteration ++) {
		long hp, av_hp, dam, av_dam;
		long *tot_hp = mem_zalloc(z_info->max_depth * sizeof(long));
		long *tot_dam = mem_zalloc(z_info->max_depth * sizeof(long));
		long *mon_count = mem_zalloc(z_info->max_depth * sizeof(long));

		/* Reset the sum of all monster power values */
		tot_mon_power = 0;

		/* Go through r_info and evaluate power ratings & flows. */
		for (i = 0; i < z_info->r_max; i++)	{

			/* Point at the "info" */
			race = &racelist[i];

			/* Set the current level */
			lvl = race->level;

			/* Maximum damage this monster can do in 10 game turns */
			dam = eval_max_dam(race, i);

			/* Adjust hit points based on resistances */
			hp = eval_hp_adjust(race);

			/* Hack -- set exp */
			if (lvl == 0)
				race->mexp = 0L;
			else {
				/* Compute depths of non-unique monsters */
				if (!rf_has(race->flags, RF_UNIQUE)) {
					long mexp = (hp * dam) / 25;
					long threat = highest_threat[i];

					/* Compute level algorithmically */
					for (j = 1; (mexp > j + 4) || (threat > j + 5);
						 mexp -= j * j, threat -= (j + 4), j++);

					/* Set level */
					lvl = MIN(( j > 250 ? 90 + (j - 250) / 20 : /* Level 90+ */
								(j > 130 ? 70 + (j - 130) / 6 :	/* Level 70+ */
								 (j > 40 ? 40 + (j - 40) / 3 :	/* Level 40+ */
								  j))), 99);

					/* Set level */
					if (arg_rebalance)
						race->level = lvl;
				}

				if (arg_rebalance) {
					/* Hack -- for Ungoliant */
					if (hp > 10000)
						race->mexp = (hp / 25) * (dam / lvl);
					else race->mexp = (hp * dam) / (lvl * 25);

					/* Round to 2 significant figures */
					if (race->mexp > 100) {
						if (race->mexp < 1000) {
							race->mexp = (race->mexp + 5) / 10;
							race->mexp *= 10;
						}
						else if (race->mexp < 10000) {
							race->mexp = (race->mexp + 50) / 100;
							race->mexp *= 100;
						}
						else if (race->mexp < 100000) {
							race->mexp = (race->mexp + 500) / 1000;
							race->mexp *= 1000;
						}
						else if (race->mexp < 1000000) {
							race->mexp = (race->mexp + 5000) / 10000;
							race->mexp *= 10000;
						}
						else if (race->mexp < 10000000) {
							race->mexp = (race->mexp + 50000) / 100000;
							race->mexp *= 100000;
						}
					}
				}
			}

			/* If we're rebalancing, this is a nop, if not, we restore the
			 * orig value */
			lvl = race->level;
			if ((lvl) && (race->mexp < 1L))
				race->mexp = 1L;

			/*
			 * Hack - We have to use an adjustment factor to prevent overflow.
			 * Try to scale evenly across all levels instead of scaling by level
			 */
			hp /= 2;
			if(hp < 1)
				hp = 1;
			final_hp[i] = hp;

			/* Define the power rating */
			power[i] = hp * dam;

			/* Adjust for group monsters, using somewhat arbitrary 
			 * multipliers for now */
			if (!rf_has(race->flags, RF_UNIQUE)) {
				if (race->friends)
					power[i] *= 3;
			}

			/* Adjust for escorts */
			if (race->friends_base) 
				power[i] *= 2;


			/* Adjust for multiplying monsters. This is modified by the speed,
			 * as fast multipliers are much worse than slow ones. We also
			 * adjust for ability to bypass walls or doors. */
			if (rf_has(race->flags, RF_MULTIPLY)) {
				int adj_power;

				if (flags_test(race->flags, RF_SIZE, RF_KILL_WALL,
							   RF_PASS_WALL, FLAG_END))
					adj_power = power[i] * adj_energy(race);
				else if (flags_test(race->flags, RF_SIZE, RF_OPEN_DOOR,
									RF_BASH_DOOR, FLAG_END))
					adj_power = power[i] * adj_energy(race) * 3 / 2;
				else
					adj_power = power[i] * adj_energy(race) / 2;

				power[i] = MAX(power[i], adj_power);
			}

			/* Update the running totals - these will be used as divisors later
			 * Total HP / dam / count for everything up to the current level */
			for (j = lvl; j < (lvl == 0 ? lvl + 1: z_info->max_depth); j++)	{
				int count = 10;

				/* Uniques don't count towards monster power on the level. */
				if (rf_has(race->flags, RF_UNIQUE)) continue;

				/* Specifically placed monsters don't count towards monster
				 * power on the level. */
				if (!(race->rarity)) continue;

				/* Hack -- provide adjustment factor to prevent overflow */
				if ((j == 90) && (race->level < 90)) {
					hp /= 10;
					dam /= 10;
				}

				if ((j == 65) && (race->level < 65)) {
					hp /= 10;
					dam /= 10;
				}

				if ((j == 40) && (race->level < 40)) {
					hp /= 10;
					dam /= 10;
				}

				/* Hack - if it's a group monster or multiplying monster, add
				 * several to the count so the averages don't get thrown off */

				if (race->friends || race->friends_base)
					count = 15;

				if (rf_has(race->flags, RF_MULTIPLY)) {
					int adj_energy_amt;

					if (flags_test(race->flags, RF_SIZE, RF_KILL_WALL,
								   RF_PASS_WALL, FLAG_END))
						adj_energy_amt = adj_energy(race);
					else if (flags_test(race->flags, RF_SIZE, RF_OPEN_DOOR,
										RF_BASH_DOOR, FLAG_END))
						adj_energy_amt = adj_energy(race) * 3 / 2;
					else
						adj_energy_amt = adj_energy(race) / 2;

					count = MAX(1, adj_energy_amt) * count;
				}

				/* Very rare monsters count less towards total monster power
				 * on the level. */
				if (race->rarity > count) {
					hp = hp * count / race->rarity;
					dam = dam * count / race->rarity;

					count = race->rarity;
				}

				tot_hp[j] += hp;
				tot_dam[j] += dam;

				mon_count[j] += count / race->rarity;
			}

		}

		/* Apply divisors now */
		for (i = 0; i < z_info->r_max; i++) {
			int new_power;

			/* Point at the "info" */
			race = &racelist[i];

			/* Extract level */
			lvl = race->level;

			/* Paranoia */
			if (tot_hp[lvl] != 0 && tot_dam[lvl] != 0) {
				scaled_power[i] = power[i];

				/* Divide by av HP and av damage for all in-level monsters */
				/* Note we have factored in the above 'adjustment factor' */
				av_hp = tot_hp[lvl] * 10 / mon_count[lvl];
				av_dam = tot_dam[lvl] * 10 / mon_count[lvl];

				/* Justifiable paranoia - avoid divide by zero errors */
				if (av_hp > 0)
					scaled_power[i] = scaled_power[i] / av_hp;
				if (av_dam > 0)
					scaled_power[i] = scaled_power[i] / av_dam;

				/* Never less than 1 */
				if (power[i] < 1)
					power[i] = 1;

				/* Set powers */
				if (arg_rebalance) {
					race->power = power[i];
					race->scaled_power = scaled_power[i];
				}

				/* Get power */
				new_power = power[i];

				/* Compute rarity algorithmically */
				for (j = 1; new_power > j; new_power -= j * j, j++);

				/* Set rarity */
				if (arg_rebalance)
					race->rarity = j;
			}
		}

		mem_free(mon_count);
		mem_free(tot_dam);
		mem_free(tot_hp);
	}

	/* Determine total monster power */
	for (i = 0; i < z_info->r_max; i++)
		tot_mon_power += r_info[i].scaled_power;

	if (dump) {
		/* Dump the power details */
		path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "mon_power.txt");
		mon_fp = file_open(buf, MODE_WRITE, FTYPE_TEXT);

		file_putf(mon_fp, "ridx|level|rarity|d_char|name|pwr|scaled|melee|spell|hp\n");

		for (i = 0; i < z_info->r_max; i++) {
			char mbstr[MB_LEN_MAX + 1] = { 0 };
			race = &r_info[i];

			/* Don't print anything for nonexistent monsters */
			if (!race->name) continue;

			wctomb(mbstr, race->d_char);
			file_putf(mon_fp, "%d|%d|%d|%s|%s|%d|%d|%d|%d|%d\n", race->ridx,
				race->level, race->rarity, mbstr, race->name,
				power[i], scaled_power[i], final_melee_dam[i],
				final_spell_dam[i], final_hp[i]);
		}

		file_close(mon_fp);
	}

	/* Write to the user directory */
	path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "new_monster.txt");

	if (text_lines_to_file(buf, write_monster_entries)) {
		msg("Failed to create file %s.new", buf);
		wrote = FALSE;
	}

	/* Free power arrays */
	mem_free(highest_threat);
	mem_free(final_spell_dam);
	mem_free(final_melee_dam);
	mem_free(final_hp);
	mem_free(scaled_power);
	mem_free(power);

	/* Success */
	return wrote ? 0 : -1;
}
Beispiel #14
0
/*
 * 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);
}
Beispiel #15
0
/**
 * This function takes a pointer to a grid info struct describing the 
 * contents of a grid location (as obtained through the function map_info)
 * and fills in the character and attr pairs for display.
 *
 * ap and cp are filled with the attr/char pair for the monster, object or 
 * floor tile that is at the "top" of the grid (monsters covering objects, 
 * which cover floor, assuming all are present).
 *
 * tap and tcp are filled with the attr/char pair for the floor, regardless
 * of what is on it.  This can be used by graphical displays with
 * transparency to place an object onto a floor tile, is desired.
 *
 * Any lighting effects are also applied to these pairs, clear monsters allow
 * the underlying colour or feature to show through (ATTR_CLEAR and
 * CHAR_CLEAR), multi-hued colour-changing (ATTR_MULTI) is applied, and so on.
 * Technically, the flag "CHAR_MULTI" is supposed to indicate that a monster 
 * looks strange when examined, but this flag is currently ignored.
 *
 * NOTES:
 * This is called pretty frequently, whenever a grid on the map display
 * needs updating, so don't overcomplicate it.
 *
 * The "zero" entry in the feature/object/monster arrays are
 * used to provide "special" attr/char codes, with "monster zero" being
 * used for the player attr/char, "object zero" being used for the "pile"
 * attr/char, and "feature zero" being used for the "darkness" attr/char.
 *
 * TODO:
 * The transformations for tile colors, or brightness for the 16x16
 * tiles should be handled differently.  One possibility would be to
 * extend feature_type with attr/char definitions for the different states.
 * This will probably be done outside of the current text->graphics mappings
 * though.
 */
void grid_data_as_text(grid_data *g, int *ap, wchar_t *cp, int *tap, wchar_t *tcp)
{
	feature_type *f_ptr = &f_info[g->f_idx];

	int a = feat_x_attr[g->lighting][f_ptr->fidx];
	wchar_t c = feat_x_char[g->lighting][f_ptr->fidx];

	/* Check for trap detection boundaries */
	if (use_graphics == GRAPHICS_NONE)
		grid_get_attr(g, &a);
	else if (g->trapborder && tf_has(f_ptr->flags, TF_FLOOR)
			 && (g->m_idx || g->first_kind)) {
		/* if there is an object or monster here, and this is a plain floor
		 * display the border here rather than an overlay below */
		a = feat_x_attr[g->lighting][FEAT_DTRAP_FLOOR];
		c = feat_x_char[g->lighting][FEAT_DTRAP_FLOOR];
	}

	/* Save the terrain info for the transparency effects */
	(*tap) = a;
	(*tcp) = c;

	/* There is a trap in this grid, and we are not hallucinating */
	if (g->trap && (!g->hallucinate))
	    /* Change graphics to indicate a trap (if visible) */
	    get_trap_graphics(cave, g, &a, &c);

	/* If there's an object, deal with that. */
	if (g->unseen_money) {
	
		/* $$$ gets an orange star*/
		a = object_kind_attr(&k_info[7]);
		c = object_kind_char(&k_info[7]);
		
	} else if (g->unseen_object) {	
	
		/* Everything else gets a red star */    
		a = object_kind_attr(&k_info[6]);
		c = object_kind_char(&k_info[6]);
		
	} else if (g->first_kind) {
		if (g->hallucinate) {
			/* Just pick a random object to display. */
			hallucinatory_object(&a, &c);
		} else if (g->multiple_objects) {
			/* Get the "pile" feature instead */
			a = object_kind_attr(&k_info[0]);
			c = object_kind_char(&k_info[0]);
		} else {
			/* Normal attr and char */
			a = object_kind_attr(g->first_kind);
			c = object_kind_char(g->first_kind);
		}
	}

	/* Handle monsters, the player and trap borders */
	if (g->m_idx > 0) {
		if (g->hallucinate) {
			/* Just pick a random monster to display. */
			hallucinatory_monster(&a, &c);
		} else if (!is_mimicking(cave_monster(cave, g->m_idx)))	{
			monster_type *m_ptr = cave_monster(cave, g->m_idx);

			byte da;
			wchar_t dc;

			/* Desired attr & char */
			da = monster_x_attr[m_ptr->race->ridx];
			dc = monster_x_char[m_ptr->race->ridx];

			/* Special handling of attrs and/or chars */
			if (da & 0x80) {
				/* Special attr/char codes */
				a = da;
				c = dc;
			} else if (OPT(purple_uniques) && 
					   rf_has(m_ptr->race->flags, RF_UNIQUE)) {
				/* Turn uniques purple if desired (violet, actually) */
				a = COLOUR_VIOLET;
				c = dc;
			} else if (rf_has(m_ptr->race->flags, RF_ATTR_MULTI) ||
					   rf_has(m_ptr->race->flags, RF_ATTR_FLICKER) ||
					   rf_has(m_ptr->race->flags, RF_ATTR_RAND)) {
				/* Multi-hued monster */
				a = m_ptr->attr ? m_ptr->attr : da;
				c = dc;
			} else if (!flags_test(m_ptr->race->flags, RF_SIZE,
								   RF_ATTR_CLEAR, RF_CHAR_CLEAR, FLAG_END)) {
				/* Normal monster (not "clear" in any way) */
				a = da;
				/* Desired attr & char. da is not used, should a be set to it?*/
				/*da = monster_x_attr[m_ptr->race->ridx];*/
				dc = monster_x_char[m_ptr->race->ridx];
				c = dc;
			} else if (a & 0x80) {
				/* Hack -- Bizarre grid under monster */
				a = da;
				c = dc;
			} else if (!rf_has(m_ptr->race->flags, RF_CHAR_CLEAR)) {
				/* Normal char, Clear attr, monster */
				c = dc;
			} else if (!rf_has(m_ptr->race->flags, RF_ATTR_CLEAR)) {
				/* Normal attr, Clear char, monster */
				a = da;
			}

			/* Store the drawing attr so we can use it elsewhere */
			m_ptr->attr = a;
		}
	} else if (g->is_player) {
		monster_race *r_ptr = &r_info[0];

		/* Get the "player" attr */
		a = monster_x_attr[r_ptr->ridx];
		if ((OPT(hp_changes_color)) && !(a & 0x80)) {
			switch(player->chp * 10 / player->mhp)
			{
			case 10:
			case  9: 
			{
				a = COLOUR_WHITE; 
				break;
			}
			case  8:
			case  7:
			{
				a = COLOUR_YELLOW;
				break;
			}
			case  6:
			case  5:
			{
				a = COLOUR_ORANGE;
				break;
			}
			case  4:
			case  3:
			{
				a = COLOUR_L_RED;
				break;
			}
			case  2:
			case  1:
			case  0:
			{
				a = COLOUR_RED;
				break;
			}
			default:
			{
				a = COLOUR_WHITE;
				break;
			}
			}
		}

		/* Get the "player" char */
		c = monster_x_char[r_ptr->ridx];
	} else if (g->trapborder && (g->f_idx) && !(g->first_kind)
			   && (use_graphics != GRAPHICS_NONE)) {
		/* No overlay is used, so we can use the trap border overlay */
		a = feat_x_attr[g->lighting][FEAT_DTRAP_WALL];
		c = feat_x_char[g->lighting][FEAT_DTRAP_WALL];
	}

	/* Result */
	(*ap) = a;
	(*cp) = c;
}
Beispiel #16
0
/**
 * Choose "logical" directions for monster movement
 */
static bool get_move(struct chunk *c, struct monster *mon, int *dir, bool *good)
{
	struct loc decoy = cave_find_decoy(c);
	struct loc target = (decoy.y && decoy.x) ? decoy :
		loc(player->px, player->py);

	int y, x;

	/* Monsters will run up to z_info->flee_range grids out of sight */
	int flee_range = z_info->max_sight + z_info->flee_range;

	bool done = false;

	/* Calculate range */
	get_move_find_range(mon);

	/* Assume we're heading towards the player */
	if (get_move_advance(c, mon)) {
		/* Extract the "pseudo-direction" */
		y = mon->target.grid.y - mon->fy;
		x = mon->target.grid.x - mon->fx;
		*good = true;
	} else {
		/* Head blindly straight for the "player" if there's no better idea */
		y = target.y - mon->fy;
		x = target.x - mon->fx;
	}

	/* Normal animal packs try to get the player out of corridors. */
	if (rf_has(mon->race->flags, RF_GROUP_AI) &&
	    !flags_test(mon->race->flags, RF_SIZE, RF_PASS_WALL, RF_KILL_WALL,
					FLAG_END)) {
		int i, open = 0;

		/* Count empty grids next to player */
		for (i = 0; i < 8; i++) {
			int ry = target.y + ddy_ddd[i];
			int rx = target.x + ddx_ddd[i];
			/* Check grid around the player for room interior (room walls count)
			 * or other empty space */
			if (square_ispassable(c, ry, rx) || square_isroom(c, ry, rx)) {
				/* One more open grid */
				open++;
			}
		}

		/* Not in an empty space and strong player */
		if ((open < 5) && (player->chp > player->mhp / 2)) {
			/* Find hiding place */
			if (get_move_find_hiding(c, mon)) {
				done = true;
				y = mon->target.grid.y - mon->fy;
				x = mon->target.grid.x - mon->fx;
			}
		}
	}

	/* Apply fear */
	if (!done && (mon->min_range == flee_range)) {
		/* Try to find safe place */
		if (!get_move_find_safety(c, mon)) {
			/* Just leg it away from the player */
			y = (-y);
			x = (-x);
		} else {
			/* Set a course for the safe place */
			get_move_flee(c, mon);
			y = mon->target.grid.y - mon->fy;
			x = mon->target.grid.x - mon->fx;
		}

		done = true;
	}

	/* Monster groups try to surround the player */
	if (!done && rf_has(mon->race->flags, RF_GROUP_AI) &&
		square_isview(c, mon->fy, mon->fx)) {
		int i, yy = mon->target.grid.y, xx = mon->target.grid.x;

		/* If we are not already adjacent */
		if (mon->cdis > 1) {
			/* Find an empty square near the player to fill */
			int tmp = randint0(8);
			for (i = 0; i < 8; i++) {
				/* Pick squares near player (pseudo-randomly) */
				yy = target.y + ddy_ddd[(tmp + i) & 7];
				xx = target.x + ddx_ddd[(tmp + i) & 7];

				/* Ignore filled grids */
				if (!square_isempty(c, yy, xx)) continue;

				/* Try to fill this hole */
				break;
			}
		}

		/* Extract the new "pseudo-direction" */
		y = yy - mon->fy;
		x = xx - mon->fx;
	}

	/* Check if the monster has already reached its target */
	if (!x && !y) return (false);

	/* Pick the correct direction */
	*dir = get_move_choose_direction(y, x);

	/* Want to move */
	return (true);
}
Beispiel #17
0
/**
 * Monster can pass through walls
 */
bool monster_passes_walls(const struct monster *mon)
{
	return flags_test(mon->race->flags, RF_SIZE, RF_PASS_WALL, RF_KILL_WALL,
					  RF_SMASH_WALL, FLAG_END);
}
Beispiel #18
0
/* 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? */
}
Beispiel #19
0
static long eval_hp_adjust(struct monster_race *race)
{
	long hp;
	int resists = 1;
	int hide_bonus = 0;

	/* Get the monster base hitpoints */
	hp = race->avg_hp;

	/* Never moves with no ranged attacks - high hit points count for less */
	if (rf_has(race->flags, RF_NEVER_MOVE) &&
		!(race->freq_innate || race->freq_spell)) {
		hp /= 2;
		if (hp < 1)
			hp = 1;
	}

	/* Just assume healers have more staying power */
	if (rsf_has(race->spell_flags, RSF_HEAL)) hp = (hp * 6) / 5;

	/* Miscellaneous improvements */
	if (rf_has(race->flags, RF_REGENERATE)) {hp *= 10; hp /= 9;}
	if (rf_has(race->flags, RF_PASS_WALL)) {hp *= 3; hp /= 2;}

	/* Calculate hide bonus */
	if (rf_has(race->flags, RF_EMPTY_MIND))
		hide_bonus += 2;
	else {
		if (rf_has(race->flags, RF_COLD_BLOOD)) hide_bonus += 1;
		if (rf_has(race->flags, RF_WEIRD_MIND)) hide_bonus += 1;
	}

	/* Invisibility */
	if (rf_has(race->flags, RF_INVISIBLE))
		hp = (hp * (race->level + hide_bonus + 1)) / MAX(1, race->level);

	/* Monsters that can teleport are a hassle, and can easily run away */
	if (flags_test(race->spell_flags, RSF_SIZE, RSF_TPORT, RSF_TELE_AWAY,
				   RSF_TELE_LEVEL, FLAG_END))
		hp = (hp * 6) / 5;

	/* Monsters that multiply are tougher to kill */
	if (rf_has(race->flags, RF_MULTIPLY)) hp *= 2;

	/* Monsters with resistances are harder to kill.
	 * Therefore effective slays / brands against them are worth more. */
	if (rf_has(race->flags, RF_IM_ACID))
		resists += 2;
	if (rf_has(race->flags, RF_IM_FIRE))
		resists += 2;
	if (rf_has(race->flags, RF_IM_COLD))
		resists += 2;
	if (rf_has(race->flags, RF_IM_ELEC))
		resists += 2;
	if (rf_has(race->flags, RF_IM_POIS))
		resists += 2;

	/* Bonus for multiple basic resists and weapon resists */
	if (resists >= 12)
		resists *= 6;
	else if (resists >= 10)
		resists *= 4;
	else if (resists >= 8)
		resists *= 3;
	else if (resists >= 6)
		resists *= 2;

	/* If quite resistant, reduce resists by defense holes */
	if (resists >= 6) {
		if (rf_has(race->flags, RF_HURT_ROCK))
			resists -= 1;
		if (rf_has(race->flags, RF_HURT_LIGHT))
			resists -= 1;
		if (!rf_has(race->flags, RF_NO_SLEEP))
			resists -= 3;
		if (!rf_has(race->flags, RF_NO_FEAR))
			resists -= 2;
		if (!rf_has(race->flags, RF_NO_CONF))
			resists -= 2;
		if (!rf_has(race->flags, RF_NO_STUN))
			resists -= 1;

		if (resists < 5)
			resists = 5;
	}

	/* If quite resistant, bonus for high resists */
	if (resists >= 3) {
		if (rf_has(race->flags, RF_IM_WATER))
			resists += 1;
		if (rf_has(race->flags, RF_IM_NETHER))
			resists += 1;
		if (rf_has(race->flags, RF_IM_NEXUS))
			resists += 1;
		if (rf_has(race->flags, RF_IM_DISEN))
			resists += 1;
	}

	/* Scale resists */
	resists = resists * 25;

	/* Monster resistances */
	if (resists < (race->ac + resists) / 3)
		hp += (hp * resists) / (150 + race->level); 	
	else
		hp += (hp * (race->ac + resists) / 3) / (150 + race->level); 			

	/* Boundary control */
	if (hp < 1)
		hp = 1;

	return (hp);
}
Beispiel #20
0
/*
 * Attempt to change an object into an ego-item -MWK-
 * Better only called by apply_magic().
 * The return value says if we picked a cursed item (if allowed) and is
 * passed on to a_m_aux1/2().
 * If no legal ego item is found, this routine returns 0, resulting in
 * an unenchanted item.
 */
static int make_ego_item(object_type *o_ptr, int level, bool force_uncursed)
{
	int i, j;

	int e_idx;

	long value, total;

	ego_item_type *e_ptr;

	alloc_entry *table = alloc_ego_table;


	/* Fail if object already is ego or artifact */
	if (o_ptr->name1) return (FALSE);
	if (o_ptr->name2) return (FALSE);

	/* Boost level (like with object base types) */
	if (level > 0)
	{
		/* Occasional "boost" */
		if (one_in_(GREAT_EGO))
		{
			/* The bizarre calculation again */
			level = 1 + (level * MAX_DEPTH / randint1(MAX_DEPTH));
		}
	}

	/* Reset total */
	total = 0L;

	/* Process probabilities */
	for (i = 0; i < alloc_ego_size; i++)
	{
		/* Default */
		table[i].prob3 = 0;

		/* Objects are sorted by depth */
		if (table[i].level > level) continue;

		/* Get the index */
		e_idx = table[i].index;

		/* Get the actual kind */
		e_ptr = &e_info[e_idx];

		/* Avoid cursed items if specified */
		if (force_uncursed && cursed_p(e_ptr)) continue;

		/* Test if this is a legal ego-item type for this object */
		for (j = 0; j < EGO_TVALS_MAX; j++)
		{
			/* Require identical base type */
			if (o_ptr->tval == e_ptr->tval[j])
			{
				/* Require sval in bounds, lower */
				if (o_ptr->sval >= e_ptr->min_sval[j])
				{
					/* Require sval in bounds, upper */
					if (o_ptr->sval <= e_ptr->max_sval[j])
					{
						/* Accept */
						table[i].prob3 = table[i].prob2;
					}
				}
			}
		}

		/* Total */
		total += table[i].prob3;
	}

	/* No legal ego-items -- create a normal unenchanted one */
	if (total == 0) return (0);


	/* Pick an ego-item */
	value = randint0(total);

	/* Find the object */
	for (i = 0; i < alloc_ego_size; i++)
	{
		/* Found the entry */
		if (value < table[i].prob3) break;

		/* Decrement */
		value = value - table[i].prob3;
	}

	/* We have one */
	e_idx = (byte)table[i].index;
	o_ptr->name2 = e_idx;

	return (flags_test(e_info[e_idx].flags, OF_SIZE, OF_CURSE_MASK, FLAG_END) ? -2 : 2);
}
Beispiel #21
0
static long eval_max_dam(struct monster_race *race, int ridx)
{
	int rlev, i;
	int melee_dam = 0, atk_dam = 0, spell_dam = 0;
	int dam = 1;

	/* Extract the monster level, force 1 for town monsters */
	rlev = ((race->level >= 1) ? race->level : 1);

	/* Assume single resist for the elemental attacks */
	spell_dam = best_spell_power(race, 1);

	/* Hack - Apply over 10 rounds */
	spell_dam *= 10;

	/* Scale for frequency and availability of mana / ammo */
	if (spell_dam) {
		int freq = race->freq_spell;

		/* Hack -- always get 1 shot */
		if (freq < 10) freq = 10;

		/* Adjust for frequency */
		spell_dam = spell_dam * freq / 100;
	}

	/* Check attacks */
	for (i = 0; i < z_info->mon_blows_max; i++) {
		int effect, method;
		random_value dice;

		if (!race->blow) break;

		/* Extract the attack infomation */
		effect = race->blow[i].effect;
		method = race->blow[i].method;
		dice = race->blow[i].dice;

		/* Assume maximum damage */
		atk_dam = eval_blow_effect(effect, dice, race->level);

		/* Factor for dangerous side effects */
		if (monster_blow_method_stun(method)) {
			/* Stun definitely most dangerous*/
			atk_dam *= 4;
			atk_dam /= 3;
		} else if (monster_blow_method_stun(method)) {
			/* Cut */
			atk_dam *= 7;
			atk_dam /= 5;
		}

		/* Normal melee attack */
		if (!rf_has(race->flags, RF_NEVER_BLOW)) {
			/* Keep a running total */
			melee_dam += atk_dam;
		}
	}

	/* Apply damage over 10 rounds. We assume that the monster has to make
	 * contact first.
	 * Hack - speed has more impact on melee as has to stay in contact with
	 * player.
	 * Hack - this is except for pass wall and kill wall monsters which can
	 * always get to the player.
	 * Hack - use different values for huge monsters as they strike out to
	 * range 2. */
		if (flags_test(race->flags, RF_SIZE, RF_KILL_WALL, RF_PASS_WALL,
					   FLAG_END))
			melee_dam *= 10;
		else
			melee_dam = melee_dam * 3 + melee_dam * adj_energy(race) / 7;

		/* Scale based on attack accuracy. We make a massive number of
		 * assumptions here and just use monster level. */
		melee_dam = melee_dam * MIN(45 + rlev * 3, 95) / 100;

		/* Hack -- Monsters that multiply ignore the following reductions */
		if (!rf_has(race->flags, RF_MULTIPLY)) {
			/*Reduce damamge potential for monsters that move randomly */
			if (flags_test(race->flags, RF_SIZE, RF_RAND_25, RF_RAND_50,
						   FLAG_END)) {
				int reduce = 100;

				if (rf_has(race->flags, RF_RAND_25)) reduce -= 25;
				if (rf_has(race->flags, RF_RAND_50)) reduce -= 50;

				/* Even moving randomly one in 8 times will hit the player */
				reduce += (100 - reduce) / 8;

				/* Adjust the melee damage */
				melee_dam = (melee_dam * reduce) / 100;
			}

			/* Monsters who can't move are much less of a combat threat */
			if (rf_has(race->flags, RF_NEVER_MOVE)) {
				if (rsf_has(race->spell_flags, RSF_TELE_TO) ||
				    rsf_has(race->spell_flags, RSF_BLINK)) {
					/* Scale for frequency */
					melee_dam = melee_dam / 5 + 4 * melee_dam *
						race->freq_spell / 500;

					/* Incorporate spell failure chance */
					if (!rf_has(race->flags, RF_STUPID))
						melee_dam = melee_dam / 5 + 4 * melee_dam *
							MIN(75 + (rlev + 3) / 4, 100) / 500;
				}
				else if (rf_has(race->flags, RF_INVISIBLE))
					melee_dam /= 3;
				else
					melee_dam /= 5;
			}
		}

		/* But keep at a minimum */
		if (melee_dam < 1) melee_dam = 1;

	/* Combine spell and melee damage */
	dam = (spell_dam + melee_dam);

	highest_threat[ridx] = dam;
	final_spell_dam[ridx] = spell_dam;
	final_melee_dam[ridx] = melee_dam;

	/* Adjust for speed - monster at speed 120 will do double damage, monster
	 * at speed 100 will do half, etc.  Bonus for monsters who can haste self */
	dam = (dam * adj_energy(race)) / 10;

	/* Adjust threat for speed -- multipliers are more threatening. */
	if (rf_has(race->flags, RF_MULTIPLY))
		highest_threat[ridx] = (highest_threat[ridx] * adj_energy(race)) / 5;

	/* Adjust threat for friends, this can be improved, but is probably good
	 * enough for now. */
	if (race->friends)
		highest_threat[ridx] *= 2;
	else if (race->friends_base)
		/* Friends base is weaker, because they are <= monster level */
		highest_threat[ridx] = highest_threat[ridx] * 3 / 2;
		
	/* But keep at a minimum */
	if (dam < 1) dam  = 1;

	/* We're done */
	return (dam);
}
Beispiel #22
0
/*
 * Determine the squelch level of an object, which is similar to its pseudo.
 *
 * The main point is when the value is undetermined given current info,
 * return the maximum possible value.
 */
static byte squelch_level_of(const object_type *o_ptr)
{
	object_kind *k_ptr = &k_info[o_ptr->k_idx];
	byte value;
	bitflag f[OF_SIZE];

	object_flags_known(o_ptr, f);

	if ((object_pval_is_visible(o_ptr)) && (o_ptr->pval < 0))
		return SQUELCH_BAD;

	/* Deal with jewelry specially. */
	if (object_is_jewelry(o_ptr))
	{
		if ((object_pval_is_visible(o_ptr)) && (o_ptr->pval > 0))
			return SQUELCH_AVERAGE;
		if ((o_ptr->to_h > 0) || (o_ptr->to_d > 0) || (o_ptr->to_a > 0))
			return SQUELCH_AVERAGE;
		if ((o_ptr->to_h < 0) || (o_ptr->to_d < 0) || (o_ptr->to_a < 0))
			return SQUELCH_BAD;

		return SQUELCH_AVERAGE;
	}

	/* And lights */
	if (o_ptr->tval == TV_LIGHT)
	{
		if (flags_test(f, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END))
			return SQUELCH_ALL;
		if ((o_ptr->to_h > 0) || (o_ptr->to_d > 0) || (o_ptr->to_a > 0))
			return SQUELCH_GOOD;
		if ((o_ptr->to_h < 0) || (o_ptr->to_d < 0) || (o_ptr->to_a < 0))
			return SQUELCH_BAD;

		return SQUELCH_AVERAGE;
	}

	if (object_was_sensed(o_ptr))
	{
		obj_pseudo_t pseudo = object_pseudo(o_ptr);

		switch (pseudo)
		{
			case INSCRIP_AVERAGE:
				value = SQUELCH_AVERAGE;
				break;

			case INSCRIP_EXCELLENT:
				/* have to assume splendid until you have tested it */
				if (object_was_worn(o_ptr))
				{
					if (object_high_resist_is_possible(o_ptr))
						value = SQUELCH_EXCELLENT_NO_SPL;
					else
						value = SQUELCH_EXCELLENT_NO_HI;
				}
				else
				{
					value = SQUELCH_ALL;
				}
				break;

			case INSCRIP_STRANGE: /* XXX Eddie perhaps some strange count as something else */
			case INSCRIP_SPLENDID:
				value = SQUELCH_ALL;
				break;
			case INSCRIP_NULL:
			case INSCRIP_SPECIAL:
				value = SQUELCH_MAX;
				break;

			/* This is the interesting case */
			case INSCRIP_MAGICAL:
				value = SQUELCH_GOOD;
				if ((object_attack_plusses_are_visible(o_ptr) || (randcalc_valid(k_ptr->to_h, o_ptr->to_h) && randcalc_valid(k_ptr->to_d, o_ptr->to_d))) &&
				    (object_defence_plusses_are_visible(o_ptr) || (randcalc_valid(k_ptr->to_a, o_ptr->to_a))) &&
				    (o_ptr->to_h <= randcalc(k_ptr->to_h, 0, MINIMISE)) &&
				    (o_ptr->to_d <= randcalc(k_ptr->to_d, 0, MINIMISE)) &&
				    (o_ptr->to_a <= randcalc(k_ptr->to_a, 0, MINIMISE)))
					value = SQUELCH_BAD;
				break;


			default:
				/* do not handle any other possible pseudo values */
				assert(0);
		}
	}
	else
	{
		if (object_was_worn(o_ptr))
			value = SQUELCH_EXCELLENT_NO_SPL; /* object would be sensed if it were splendid */
		else if (object_is_known_not_artifact(o_ptr))
			value = SQUELCH_ALL;
		else
			value = SQUELCH_MAX;
	}

	return value;
}