/* テスト */
/*
 * File: wiz-spoil.c
 * Purpose: Spoiler generation
 *
 * Copyright (c) 1997 Ben Harrison, and others
 *
 * This work is free software; you can redistribute it and/or modify it
 * under the terms of either:
 *
 * a) the GNU General Public License as published by the Free Software
 *    Foundation, version 2, or
 *
 * b) the "Angband licence":
 *    This software may be copied and distributed for educational, research,
 *    and not for profit purposes provided that this copyright and statement
 *    are included in all such copies.  Other copyrights may also apply.
 */

extern "C"
{
#include "angband.h"
#include "z-file.h"
#include "wizard.h"
#include "cmds.h"
#include "object/tvalsval.h"
}

#ifdef ALLOW_SPOILERS

extern void message_flush(void);
extern size_t object_desc(_TCHAR *buf, size_t max, const object_type *o_ptr, bool prefix, int mode);
extern size_t strnfmt(_TCHAR *buf, size_t max, const _TCHAR *fmt, ...);
extern void msg_print(const _TCHAR *msg);
extern void screen_save(void);
extern void screen_load(void);
extern void prt(const _TCHAR *str, int row, int col);
extern void bell(const _TCHAR *reason);

/*
 * The spoiler file being created
 */
static ang_file *fh = NULL;

/*
 * Write out `n' of the character `c' to the spoiler file
 */
static void spoiler_out_n_chars(int n, char c)
{
	while (--n >= 0) file_writec(fh, c);
}

/*
 * Write out `n' blank lines to the spoiler file
 */
static void spoiler_blanklines(int n)
{
	spoiler_out_n_chars(n, '\n');
}

/*
 * Write a line to the spoiler file and then "underline" it with hypens
 */
static void spoiler_underline(const _TCHAR *str, char c)
{
	text_out(__T("%s"), str);
	text_out(L"\n");
	spoiler_out_n_chars(_tcslen(str), c);
	text_out(L"\n");
}

/*
 * Item Spoilers by Ben Harrison (benh@phial.com)
 */

/*
 * The basic items categorized by type
 */
static const grouper group_item[] =
{
	{ TV_SHOT,		L"Ammo" },
	{ TV_ARROW,		  NULL },
	{ TV_BOLT,		  NULL },

	{ TV_BOW,		L"Bows" },

	{ TV_SWORD,		L"Weapons" },
	{ TV_POLEARM,	  NULL },
	{ TV_HAFTED,	  NULL },
	{ TV_DIGGING,	  NULL },

	{ TV_SOFT_ARMOR,	L"Armour (Body)" },
	{ TV_HARD_ARMOR,	  NULL },
	{ TV_DRAG_ARMOR,	  NULL },

	{ TV_CLOAK,		L"Armour (Misc)" },
	{ TV_SHIELD,	  NULL },
	{ TV_HELM,		  NULL },
	{ TV_CROWN,		  NULL },
	{ TV_GLOVES,	  NULL },
	{ TV_BOOTS,		  NULL },

	{ TV_AMULET,	L"Amulets" },
	{ TV_RING,		L"Rings" },

	{ TV_SCROLL,	L"Scrolls" },
	{ TV_POTION,	L"Potions" },
	{ TV_FOOD,		L"Food" },

	{ TV_ROD,		L"Rods" },
	{ TV_WAND,		L"Wands" },
	{ TV_STAFF,		L"Staffs" },

	{ TV_MAGIC_BOOK,	L"Books (Mage)" },
	{ TV_PRAYER_BOOK,	L"Books (Priest)" },

	{ TV_CHEST,		L"Chests" },

	{ TV_SPIKE,		L"Various" },
	{ TV_LITE,		  NULL },
	{ TV_FLASK,		  NULL },
	{ TV_JUNK,		  NULL },
	{ TV_BOTTLE,	  NULL },
	{ TV_SKELETON,	  NULL },

	{ 0, __T("") }
};

/*
 * Describe the kind
 */
static void kind_info(_TCHAR *buf, size_t buf_len,
                      _TCHAR *dam, size_t dam_len,
                      _TCHAR *wgt, size_t wgt_len,
                      int *lev, s32b *val, int k)
{
	object_kind *k_ptr;

	object_type *i_ptr;
	object_type object_type_body;

	/* Get local object */
	i_ptr = &object_type_body;

	/* Prepare a fake item */
	object_prep(i_ptr, k);

	/* Obtain the "kind" info */
	k_ptr = &k_info[i_ptr->k_idx];

	/* Cancel bonuses */
	i_ptr->pval = 0;
	i_ptr->to_a = 0;
	i_ptr->to_h = 0;
	i_ptr->to_d = 0;

	/* Level */
	(*lev) = k_ptr->level;

	/* Make known */
	i_ptr->ident |= (IDENT_KNOWN);

	/* Value */
	(*val) = object_value(i_ptr, 1);

	/* Description (too brief) */
	if (buf)
		object_desc(buf, buf_len, i_ptr, FALSE,
				ODESC_BASE | ODESC_SPOIL);

	/* Weight */
	if (wgt)
		strnfmt(wgt, wgt_len, L"%3d.%d",
				i_ptr->weight / 10, i_ptr->weight % 10);

	/* Hack */
	if (!dam)
		return;

	/* Misc info */
	dam[0] = 0;

	/* Damage */
	switch (i_ptr->tval)
	{
		/* Bows */
		case TV_BOW:
		{
			break;
		}

		/* Ammo */
		case TV_SHOT:
		case TV_BOLT:
		case TV_ARROW:
		{
			strnfmt(dam, dam_len, L"%dd%d", i_ptr->dd, i_ptr->ds);
			break;
		}

		/* Weapons */
		case TV_HAFTED:
		case TV_POLEARM:
		case TV_SWORD:
		case TV_DIGGING:
		{
			strnfmt(dam, dam_len, L"%dd%d", i_ptr->dd, i_ptr->ds);
			break;
		}

		/* Armour */
		case TV_BOOTS:
		case TV_GLOVES:
		case TV_CLOAK:
		case TV_CROWN:
		case TV_HELM:
		case TV_SHIELD:
		case TV_SOFT_ARMOR:
		case TV_HARD_ARMOR:
		case TV_DRAG_ARMOR:
		{
			strnfmt(dam, dam_len, L"%d", i_ptr->ac);
			break;
		}
	}
}

/*
 * Create a spoiler file for items
 */
static void spoil_obj_desc(_TCHAR *fname)
{
	int i, k, s, t, n = 0;

	u16b who[200];

	_TCHAR buf[1024];

	_TCHAR wgt[80];
	_TCHAR dam[80];

	const _TCHAR *format = L"%-51s  %7s%6s%4s%9s\n";

	/* Open the file */
	path_build(buf, _countof(buf), ANGBAND_DIR_USER, fname);
	fh = file_open(buf, MODE_WRITE, FTYPE_TEXT);

	/* Oops */
	if (!fh)
	{
		msg_print(__T("Cannot create spoiler file."));
		return;
	}

	/* Header */
	file_putf(fh, L"Spoiler File -- Basic Items (%s)\n\n\n", VERSION_STRING);

	/* More Header */
	file_putf(fh, format, L"Description", "Dam/AC", "Wgt", "Lev", "Cost");
	file_putf(fh, format, L"----------------------------------------",
	        L"------", L"---", L"---", L"----");

	/* List the groups */
	for (i = 0; TRUE; i++)
	{
		/* Write out the group title */
		if (group_item[i].name)
		{
			/* Hack -- bubble-sort by cost and then level */
			for (s = 0; s < n - 1; s++)
			{
				for (t = 0; t < n - 1; t++)
				{
					int i1 = t;
					int i2 = t + 1;

					int e1;
					int e2;

					s32b t1;
					s32b t2;

					kind_info(NULL, 0, NULL, 0, NULL, 0, &e1, &t1, who[i1]);
					kind_info(NULL, 0, NULL, 0, NULL, 0, &e2, &t2, who[i2]);

					if ((t1 > t2) || ((t1 == t2) && (e1 > e2)))
					{
						int tmp = who[i1];
						who[i1] = who[i2];
						who[i2] = tmp;
					}
				}
			}

			/* Spoil each item */
			for (s = 0; s < n; s++)
			{
				int e;
				s32b v;

				/* Describe the kind */
				kind_info(buf, _countof(buf), dam, _countof(dam), wgt, _countof(wgt), &e, &v, who[s]);

				/* Dump it */
				file_putf(fh, L"  %-51s%7s%6s%4d%9ld\n",
				        buf, dam, wgt, e, (long)(v));
			}

			/* Start a new set */
			n = 0;

			/* Notice the end */
			if (!group_item[i].tval) break;

			/* Start a new set */
			file_putf(fh, L"\n\n%s\n\n", group_item[i].name);
		}

		/* Get legal item types */
		for (k = 1; k < z_info->k_max; k++)
		{
			object_kind *k_ptr = &k_info[k];

			/* Skip wrong tval's */
			if (k_ptr->tval != group_item[i].tval) continue;

			/* Hack -- Skip instant-artifacts */
			if (k_ptr->flags[2] & (TR2_INSTA_ART)) continue;

			/* Save the index */
			who[n++] = k;
		}
	}

	/* Check for errors */
	if (!file_close(fh))
	{
		msg_print(__T("Cannot close spoiler file."));
		return;
	}

	/* Message */
	msg_print(__T("Successfully created a spoiler file."));
}

/*
 * Artifact Spoilers by: randy@PICARD.tamu.edu (Randy Hutson)
 *
 * (Mostly) rewritten in 2002 by Andrew Sidwell and Robert Ruehlmann.
 */

/*
 * The artifacts categorized by type
 */
static const grouper group_artifact[] =
{
	{ TV_SWORD,         L"Edged Weapons" },
	{ TV_POLEARM,       L"Polearms" },
	{ TV_HAFTED,        L"Hafted Weapons" },
	{ TV_BOW,           L"Bows" },
	{ TV_DIGGING,       L"Diggers" },

	{ TV_SOFT_ARMOR,    L"Body Armor" },
	{ TV_HARD_ARMOR,    NULL },
	{ TV_DRAG_ARMOR,    NULL },

	{ TV_CLOAK,         L"Cloaks" },
	{ TV_SHIELD,        L"Shields" },
	{ TV_HELM,          L"Helms/Crowns" },
	{ TV_CROWN,         NULL },
	{ TV_GLOVES,        L"Gloves" },
	{ TV_BOOTS,         L"Boots" },

	{ TV_LITE,          L"Light Sources" },
	{ TV_AMULET,        L"Amulets" },
	{ TV_RING,          L"Rings" },

	{ 0, NULL }
};

/*
 * Hack -- Create a "forged" artifact
 */
bool make_fake_artifact(object_type *o_ptr, byte name1)
{
	int i;

	artifact_type *a_ptr = &a_info[name1];

	/* Ignore "empty" artifacts */
	if (!a_ptr->name) return FALSE;

	/* Get the "kind" index */
	i = lookup_kind(a_ptr->tval, a_ptr->sval);

	/* Oops */
	if (!i) return (FALSE);

	/* Create the artifact */
	object_prep(o_ptr, i);

	/* Save the name */
	o_ptr->name1 = name1;

	/* Extract the 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" flag */
	if (a_ptr->flags[2] & (TR2_LIGHT_CURSE))
		o_ptr->flags[2] |= TR2_LIGHT_CURSE;

	/* Success */
	return (TRUE);
}

/*
 * Create a spoiler file for artifacts
 */
static void spoil_artifact(_TCHAR *fname)
{
	int i, j;

	object_type *i_ptr;
	object_type object_type_body;

	_TCHAR buf[1024];

	/* Build the filename */
	path_build(buf, _countof(buf), ANGBAND_DIR_USER, fname);
	fh = file_open(buf, MODE_WRITE, FTYPE_TEXT);

	/* Oops */
	if (!fh)
	{
		msg_print(__T("Cannot create spoiler file."));
		return;
	}

	/* Dump to the spoiler file */
	text_out_hook = text_out_to_file;
	text_out_file = fh;

	/* Dump the header */
	spoiler_underline(format(L"Artifact Spoilers for %s %s",
	                         VERSION_NAME, VERSION_STRING), '=');

	/* List the artifacts by tval */
	for (i = 0; group_artifact[i].tval; i++)
	{
		/* Write out the group title */
		if (group_artifact[i].name)
		{
			spoiler_blanklines(2);
			spoiler_underline(group_artifact[i].name, '=');
			spoiler_blanklines(1);
		}

		/* Now search through all of the artifacts */
		for (j = 1; j < z_info->a_max; ++j)
		{
			artifact_type *a_ptr = &a_info[j];
			_TCHAR buf[80];

			/* We only want objects in the current group */
			if (a_ptr->tval != group_artifact[i].tval) continue;

			/* Get local object */
			i_ptr = &object_type_body;

			/* Wipe the object */
			object_wipe(i_ptr);

			/* Attempt to "forge" the artifact */
			if (!make_fake_artifact(i_ptr, (byte)j)) continue;

			/* Grab artifact name */
			object_desc(buf, _countof(buf), i_ptr, TRUE,
					ODESC_COMBAT | ODESC_SPOIL);

			/* Print name and underline */
			spoiler_underline(buf, '-');

			/* Write out the artifact description to the spoiler file */
			object_info_spoil(i_ptr);

			/*
			 * Determine the minimum depth an artifact can appear, its rarity,
			 * its weight, and its value in gold pieces.
			 */
			text_out(__T("\nLevel %u, Rarity %u, %d.%d lbs, %ld AU\n"), 
					a_ptr->level, a_ptr->rarity, (a_ptr->weight / 10), 
					(a_ptr->weight % 10), ((long)a_ptr->cost));

			/* Terminate the entry */
			spoiler_blanklines(2);
		}
	}

	/* Check for errors */
	if (!file_close(fh))
	{
		msg_print(__T("Cannot close spoiler file."));
		return;
	}

	/* Message */
	msg_print(__T("Successfully created a spoiler file."));
}

/*
 * Create a spoiler file for monsters
 */
static void spoil_mon_desc(_TCHAR *fname)
{
	int i, n = 0;

	_TCHAR buf[1024];

	_TCHAR nam[80];
	_TCHAR lev[80];
	_TCHAR rar[80];
	_TCHAR spd[80];
	_TCHAR ac[80];
	_TCHAR hp[80];
	_TCHAR exp[80];

	u16b *who;
	u16b why = 2;

	/* Build the filename */
	path_build(buf, _countof(buf), ANGBAND_DIR_USER, fname);
	fh = file_open(buf, MODE_WRITE, FTYPE_TEXT);

	/* Oops */
	if (!fh)
	{
		msg_print(__T("Cannot create spoiler file."));
		return;
	}

	/* Dump the header */
	file_putf(fh, L"Monster Spoilers for %s Version %s\n",
	        VERSION_NAME, VERSION_STRING);
	file_putf(fh, L"------------------------------------------\n\n");

	/* Dump the header */
	file_putf(fh, L"%-40.40s%4s%4s%6s%8s%4s  %11.11s\n",
	        L"Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info");
	file_putf(fh, L"%-40.40s%4s%4s%6s%8s%4s  %11.11s\n",
	        L"----", "---", "---", "---", "--", "--", "-----------");

	/* Allocate the "who" array */
	who = C_ZNEW(z_info->r_max, u16b);

	/* Scan the monsters (except the ghost) */
	for (i = 1; i < z_info->r_max - 1; i++)
	{
		monster_race *r_ptr = &r_info[i];

		/* Use that monster */
		if (r_ptr->name) who[n++] = (u16b)i;
	}

	/* Select the sort method */
	ang_sort_comp = ang_sort_comp_hook;
	ang_sort_swap = ang_sort_swap_hook;

	/* Sort the array by dungeon depth of monsters */
	ang_sort(who, &why, n);

	/* Scan again */
	for (i = 0; i < n; i++)
	{
		monster_race *r_ptr = &r_info[who[i]];

		_TCHAR *name = (r_name + r_ptr->name);

		/* Get the "name" */
		if (r_ptr->flags[0] & (RF0_QUESTOR))
		{
			strnfmt(nam, _countof(nam), L"[Q] %s", name);
		}
		else if (r_ptr->flags[0] & (RF0_UNIQUE))
		{
			strnfmt(nam, _countof(nam), L"[U] %s", name);
		}
		else
		{
			strnfmt(nam, _countof(nam), L"The %s", name);
		}

		/* Level */
		strnfmt(lev, _countof(lev), L"%d", r_ptr->level);

		/* Rarity */
		strnfmt(rar, _countof(rar), L"%d", r_ptr->rarity);

		/* Speed */
		if (r_ptr->speed >= 110)
			strnfmt(spd, _countof(spd), L"+%d", (r_ptr->speed - 110));
		else
			strnfmt(spd, _countof(spd), L"-%d", (110 - r_ptr->speed));

		/* Armor Class */
		strnfmt(ac, _countof(ac), L"%d", r_ptr->ac);

		/* Hitpoints */
		strnfmt(hp, _countof(hp), L"%d", r_ptr->avg_hp);

		/* Experience */
		strnfmt(exp, _countof(exp), L"%ld", (long)(r_ptr->mexp));

		/* Hack -- use visual instead */
		strnfmt(exp, _countof(exp), L"%s '%c'", attr_to_text(r_ptr->d_attr), r_ptr->d_char);

		/* Dump the info */
		file_putf(fh, L"%-40.40s%4s%4s%6s%8s%4s  %11.11s\n",
		        nam, lev, rar, spd, hp, ac, exp);
	}

	/* End it */
	file_putf(fh, L"\n");

	/* Free the "who" array */
	FREE(who);

	/* Check for errors */
	if (!file_close(fh))
	{
		msg_print(__T("Cannot close spoiler file."));
		return;
	}

	/* Worked */
	msg_print(__T("Successfully created a spoiler file."));
}

/*
 * Monster spoilers originally by: smchorse@ringer.cs.utsa.edu (Shawn McHorse)
 */

/*
 * Create a spoiler file for monsters (-SHAWN-)
 */
static void spoil_mon_info(_TCHAR *fname)
{
	_TCHAR buf[1024];
	int i, n;
	u16b why = 2;
	u16b *who;
	int count = 0;

	/* Open the file */
	path_build(buf, _countof(buf), ANGBAND_DIR_USER, fname);
	fh = file_open(buf, MODE_WRITE, FTYPE_TEXT);

	/* Oops */
	if (!fh)
	{
		msg_print(__T("Cannot create spoiler file."));
		return;
	}

	/* Dump to the spoiler file */
	text_out_hook = text_out_to_file;
	text_out_file = fh;

	/* Dump the header */
	text_out(__T("Monster Spoilers for %s Version %s\n"), 
			VERSION_NAME, VERSION_STRING);
	text_out(L"------------------------------------------\n\n");

	/* Allocate the "who" array */
	who = C_ZNEW(z_info->r_max, u16b);

	/* Scan the monsters */
	for (i = 1; i < z_info->r_max; i++)
	{
		monster_race *r_ptr = &r_info[i];

		/* Use that monster */
		if (r_ptr->name) who[count++] = (u16b)i;
	}

	/* Select the sort method */
	ang_sort_comp = ang_sort_comp_hook;
	ang_sort_swap = ang_sort_swap_hook;

	/* Sort the array by dungeon depth of monsters */
	ang_sort(who, &why, count);

	/*
	 * List all monsters in order (except the ghost).
	 */
	for (n = 0; n < count; n++)
	{
		int r_idx = who[n];
		monster_race *r_ptr = &r_info[r_idx];

		/* Prefix */
		if (r_ptr->flags[0] & RF0_QUESTOR)
		{
			text_out(L"[Q] ");
		}
		else if (r_ptr->flags[0] & RF0_UNIQUE)
		{
			text_out(L"[U] ");
		}
		else
		{
			text_out(L"The ");
		}
		/* Name */
		text_out(__T("%s  ("), (r_name + r_ptr->name));      /* ---)--- */

		/* Color */
		text_out(attr_to_text(r_ptr->d_attr));

		/* Symbol --(-- */
		text_out(__T(" '%c')\n"), r_ptr->d_char);

		/* Indent */
		text_out(L"=== ");

		/* Number */
		text_out(__T("Num:%d  "), r_idx);

		/* Level */
		text_out(__T("Lev:%d  "), r_ptr->level);

		/* Rarity */
		text_out(__T("Rar:%d  "), r_ptr->rarity);

		/* Speed */
		if (r_ptr->speed >= 110)
		{
			text_out(__T("Spd:+%d  "), (r_ptr->speed - 110));
		}
		else
		{
			text_out(__T("Spd:-%d  "), (110 - r_ptr->speed));
		}
		/* Hitpoints */
		text_out(__T("Hp:%d  "), r_ptr->avg_hp);

		/* Armor Class */
		text_out(__T("Ac:%d  "), r_ptr->ac);

		/* Experience */
		text_out(__T("Exp:%ld\n"), (long)(r_ptr->mexp));

		/* Describe */
		describe_monster(r_idx, TRUE);

		/* Terminate the entry */
		text_out(L"\n");
	}
	/* Free the "who" array */
	FREE(who);

	/* Check for errors */
	if (!file_close(fh))
	{
		msg_print(__T("Cannot close spoiler file."));
		return;
	}
	msg_print(__T("Successfully created a spoiler file."));
}

/*
 * Create Spoiler files
 */
void do_cmd_spoilers(void)
{
	_TCHAR ch;

	/* Save screen */
	screen_save();

	/* Interact */
	while (1)
	{
		/* Clear screen */
		Term_clear();

		/* Info */
		prt(__T("Create a spoiler file."), 2, 0);

		/* Prompt for a file */
		prt(__T("(1) Brief Object Info (obj-desc.spo)"), 5, 5);
		prt(__T("(2) Brief Artifact Info (artifact.spo)"), 6, 5);
		prt(__T("(3) Brief Monster Info (mon-desc.spo)"), 7, 5);
		prt(__T("(4) Full Monster Info (mon-info.spo)"), 8, 5);

		/* Prompt */
		prt(__T("Command: "), 12, 0);

		/* Get a choice */
		ch = inkey();

		/* Escape */
		if (ch == ESCAPE)
		{
			break;
		}
		/* Option (1) */
		else if (ch == '1')
		{
			spoil_obj_desc(L"obj-desc.spo");
		}
		/* Option (2) */
		else if (ch == '2')
		{
			spoil_artifact(L"artifact.spo");
		}
		/* Option (3) */
		else if (ch == '3')
		{
			spoil_mon_desc(L"mon-desc.spo");
		}

		/* Option (4) */
		else if (ch == '4')
		{
			spoil_mon_info(L"mon-info.spo");
		}
		else /* Oops */
		{
			bell(L"Illegal command for spoilers!");
		}
		/* Flush messages */
		message_flush();
	}
	/* Load screen */
	screen_load();
}

#endif
