Ejemplo n.º 1
0
/**
 * Save the lore to a file in the user directory.
 *
 * \param path is the path to the filename
 *
 * \returns true on success, false otherwise.
 */
bool dump_save(const char *path)
{
	if (text_lines_to_file(path, write_character_dump)) {
		msg("Failed to create file %s.new", path);
		return false;
	}

	return true;
}
Ejemplo n.º 2
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;
}