// DMSmcSrmModDlg.cpp : インプリメンテーション ファイル
//

#include "stdafx.h"
#include "DMSmcSrmMod.h"
#include "DMSmcSrmModDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDMSmcSrmModDlg ダイアログ

CDMSmcSrmModDlg::CDMSmcSrmModDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CDMSmcSrmModDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDMSmcSrmModDlg)
	m_nCurAntiFire = 0;
	m_nMaxAntiFire = 0;
	m_nCurAntiMajic = 0;
	m_nMaxAntiMajic = 0;
	m_nCurDex = 0;
	m_nMaxDex = 0;
	m_nCurHP = 0;
	m_nMaxHP = 0;
	m_nCurMana = 0;
	m_nMaxMana = 0;
	m_strFile = _T("");
	m_nCurSta = 0;
	m_nMaxSta = 0;
	m_nCurStr = 0;
	m_nMaxStr = 0;
	m_nCurVit = 0;
	m_nMaxVit = 0;
	m_nCurFood = 0;
	m_nCurWater = 0;
	m_nCurWiz = 0;
	m_nMaxWiz = 0;
	m_iX = 0;
	m_iY = 0;
	m_strSk1 = _T("");
	m_strSk2 = _T("");
	m_strSk3 = _T("");
	m_strSk4 = _T("");
	m_strPlayers = _T("");
	m_strLv = _T("");
	//}}AFX_DATA_INIT
	// メモ: LoadIcon は Win32 の DestroyIcon のサブシーケンスを要求しません。
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	m_nDir = 0;
	m_nPlayers = 0;
	m_nLevel = 0;
}

void CDMSmcSrmModDlg::DoDataExchange(CDataExchange* pDX)
{
	if (pDX->m_bSaveAndValidate == 0) {
		m_strPlayers.Format("%d", m_nPlayers);
	}

	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDMSmcSrmModDlg)
	DDX_Control(pDX, IDC_COMBO_LEVEL, m_wndLv);
	DDX_Control(pDX, IDC_STATIC_MAP, m_wndAtlas);
	DDX_Control(pDX, IDC_COMBO_DIR, m_wndDir);
	DDX_Control(pDX, IDC_EDIT_SRM_FILE, m_wndSRMFile);
	DDX_Control(pDX, IDC_COMBO_SK4, m_wndSk4);
	DDX_Control(pDX, IDC_COMBO_SK3, m_wndSk3);
	DDX_Control(pDX, IDC_COMBO_SK2, m_wndSk2);
	DDX_Control(pDX, IDC_COMBO_SK1, m_wndSk1);
	DDX_Control(pDX, IDC_TAB_PLAYER, m_wndPlayer);
	DDX_Text(pDX, IDC_EDIT_AF1, m_nCurAntiFire);
	DDX_Text(pDX, IDC_EDIT_AF2, m_nMaxAntiFire);
	DDX_Text(pDX, IDC_EDIT_AM1, m_nCurAntiMajic);
	DDX_Text(pDX, IDC_EDIT_AM2, m_nMaxAntiMajic);
	DDX_Text(pDX, IDC_EDIT_DEX1, m_nCurDex);
	DDX_Text(pDX, IDC_EDIT_DEX2, m_nMaxDex);
	DDX_Text(pDX, IDC_EDIT_HP1, m_nCurHP);
	DDX_Text(pDX, IDC_EDIT_HP2, m_nMaxHP);
	DDX_Text(pDX, IDC_EDIT_MANA1, m_nCurMana);
	DDX_Text(pDX, IDC_EDIT_MANA2, m_nMaxMana);
	DDX_Text(pDX, IDC_EDIT_SRM_FILE, m_strFile);
	DDX_Text(pDX, IDC_EDIT_STA1, m_nCurSta);
	DDX_Text(pDX, IDC_EDIT_STA2, m_nMaxSta);
	DDX_Text(pDX, IDC_EDIT_STR1, m_nCurStr);
	DDX_Text(pDX, IDC_EDIT_STR2, m_nMaxStr);
	DDX_Text(pDX, IDC_EDIT_VIT1, m_nCurVit);
	DDX_Text(pDX, IDC_EDIT_VIT2, m_nMaxVit);
	DDX_Text(pDX, IDC_EDIT_FOOD, m_nCurFood);
	DDX_Text(pDX, IDC_EDIT_WATER, m_nCurWater);
	DDX_Text(pDX, IDC_EDIT_WIS1, m_nCurWiz);
	DDX_Text(pDX, IDC_EDIT_WIS2, m_nMaxWiz);
	DDX_Text(pDX, IDC_EDIT_X, m_iX);
	DDX_Text(pDX, IDC_EDIT_Y, m_iY);
	DDX_CBString(pDX, IDC_COMBO_SK1, m_strSk1);
	DDX_CBString(pDX, IDC_COMBO_SK2, m_strSk2);
	DDX_CBString(pDX, IDC_COMBO_SK3, m_strSk3);
	DDX_CBString(pDX, IDC_COMBO_SK4, m_strSk4);
	DDX_CBString(pDX, IDC_COMBO_NP, m_strPlayers);
	DDX_CBString(pDX, IDC_COMBO_LEVEL, m_strLv);
	//}}AFX_DATA_MAP

	if (pDX->m_bSaveAndValidate != 0) {
		m_nPlayers = _ttoi(m_strPlayers);
	}

	if (pDX->m_bSaveAndValidate) {
		m_nDir = m_wndDir.GetCurSel();
		m_nLevel = m_wndLv.GetCurSel();
	} else {
		m_wndDir.SetCurSel(m_nDir);
		m_wndLv.SetCurSel(m_nLevel);
	}
}

BEGIN_MESSAGE_MAP(CDMSmcSrmModDlg, CDialog)
	//{{AFX_MSG_MAP(CDMSmcSrmModDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_REF, OnButtonRef)
	ON_NOTIFY(TCN_SELCHANGING, IDC_TAB_PLAYER, OnSelChangingTabPlayer)
	ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_PLAYER, OnSelChangeTabPlayer)
	ON_BN_CLICKED(IDC_BUTTON_SRM_READ, OnButtonSrmRead)
	ON_BN_CLICKED(IDC_BUTTON_SRM_WRITE, OnButtonSrmWrite)
	ON_CBN_EDITCHANGE(IDC_COMBO_LEVEL, OnEditChangeComboLevel)
	ON_CBN_SELCHANGE(IDC_COMBO_LEVEL, OnSelChangeComboLevel)
	//}}AFX_MSG_MAP
	ON_CONTROL(PN_SELCHANGE, IDC_STATIC_MAP, OnSelChangeMap)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDMSmcSrmModDlg メッセージ ハンドラ

BOOL CDMSmcSrmModDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// このダイアログ用のアイコンを設定します。フレームワークはアプリケーションのメイン
	// ウィンドウがダイアログでない時は自動的に設定しません。
	SetIcon(m_hIcon, TRUE);			// 大きいアイコンを設定
	SetIcon(m_hIcon, FALSE);		// 小さいアイコンを設定

	LOGFONT lf;
	ZeroMemory(&lf, sizeof(LOGFONT));
	GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
	m_font.DeleteObject();
	m_font.CreateFontIndirect(&lf);
	TEXTMETRIC tm;
	{
		CClientDC dc(this);
		HGDIOBJ hObj = dc.SelectObject(m_font.m_hObject);
		dc.GetTextMetrics(&tm);
		dc.SelectObject(hObj);
	}
	
	m_wndPlayer.InsertItem(0, "Player 1");
	m_wndPlayer.InsertItem(1, "Player 2");
	m_wndPlayer.InsertItem(2, "Player 3");
	m_wndPlayer.InsertItem(3, "Player 4");

	UINT i;

	CComboBox *pSkWnds[4] = {&m_wndSk1, &m_wndSk2, &m_wndSk3, &m_wndSk4};
	static const LPCTSTR pszSkTbl[16] = {
		"0",
		"2",
		"4",
		"8",
		"16",
		"32",
		"64",
		"128",
		"256",
		"512",
		"1024",
		"2048",
		"4096",
		"8192",
		"16384",
		"32768",
	};
	for (i = 0; i < 4; i++) {
		pSkWnds[i]->SetFont(&m_font);
		pSkWnds[i]->SetItemHeight(-1, (3) + tm.tmHeight + tm.tmInternalLeading + tm.tmExternalLeading);
		for (UINT j = 0; j < 16; j++)
			pSkWnds[i]->AddString(pszSkTbl[j]);
	}
	
	return TRUE;  // TRUE を返すとコントロールに設定したフォーカスは失われません。
}

// もしダイアログボックスに最小化ボタンを追加するならば、アイコンを描画する
// コードを以下に記述する必要があります。MFC アプリケーションは document/view
// モデルを使っているので、この処理はフレームワークにより自動的に処理されます。

void CDMSmcSrmModDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 描画用のデバイス コンテキスト

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// クライアントの矩形領域内の中央
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// アイコンを描画します。
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// システムは、ユーザーが最小化ウィンドウをドラッグしている間、
// カーソルを表示するためにここを呼び出します。
HCURSOR CDMSmcSrmModDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CDMSmcSrmModDlg::OnButtonRef() 
{
	if (!UpdateData()) return;

	const DWORD style = OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_LONGNAMES|OFN_PATHMUSTEXIST;
	CFileDialog wndDlg(TRUE, "srm", m_strFile, style, "SRM files (*.srm)|*.srm|All (*.*)|*.*||", this);

	int r = wndDlg.DoModal();
	if (r != IDOK) return;

	m_strFile = wndDlg.GetPathName();

	UpdateData(FALSE);
}

void CDMSmcSrmModDlg::OnSelChangingTabPlayer(NMHDR* pNMHDR, LRESULT* pResult) 
{
	if (!UpdateData()) return;

	revertPlayer(m_wndPlayer.GetCurFocus() & 3, FALSE);
	
	*pResult = 0;
}

void CDMSmcSrmModDlg::OnSelChangeTabPlayer(NMHDR* pNMHDR, LRESULT* pResult) 
{
	revertPlayer(m_wndPlayer.GetCurFocus() & 3, TRUE);

	UpdateData(FALSE);
	
	*pResult = 0;
}

void CDMSmcSrmModDlg::OnButtonSrmRead() 
{
	if (!UpdateData()) return;

	if (!LoadFrom(m_strFile)) return;

	revertPlayer(m_wndPlayer.GetCurFocus() & 3, TRUE);

	UpdateData(FALSE);

	m_wndAtlas.SetCurMap(m_nLevel);
	m_wndAtlas.SetCursorPos(CPoint(m_iX, m_iY));
}

void CDMSmcSrmModDlg::OnButtonSrmWrite() 
{
	if (!UpdateData()) return;

	revertPlayer(m_wndPlayer.GetCurFocus() & 3, FALSE);

	SaveTo(m_strFile);
}

void readByteAt(CFile &file, UINT nPos, UINT &x)
{
	VERIFY(file.Seek(nPos, CFile::begin) == (LONG)nPos);

	x = 0;
	file.Read(&x, 1);
}

void writeByteAt(CFile &file, UINT nPos, UINT x)
{
	VERIFY(file.Seek(nPos, CFile::begin) == (LONG)nPos);

	file.Write(&x, 1);
}

void readWordAt(CFile &file, UINT nPos, UINT &x)
{
	VERIFY(file.Seek(nPos, CFile::begin) == (LONG)nPos);

	union {
		BYTE b[2];
		WORD x;
	} z;
	file.Read(&z.x, 2);
	x = MAKEWORD(z.b[0], z.b[1]);
}

void writeWordAt(CFile &file, UINT nPos, UINT x)
{
	VERIFY(file.Seek(nPos, CFile::begin) == (LONG)nPos);

	union {
		BYTE b[2];
		WORD x;
	} z;
	z.x = x;
	x = MAKEWORD(z.b[0], z.b[1]);
	file.Write(&z, 2);
}

BOOL CDMSmcSrmModDlg::Serialize(LPCTSTR pszFileIn, BOOL fLoad)
{
	TRY
		CFile fileIn(pszFileIn, fLoad ? CFile::modeRead : CFile::modeReadWrite);

		if (!chkSaveData(fileIn)) {
			AfxMessageBox("Invalid 'DM SFX SAVE DATA'");
			return FALSE;
		}

		serializeWordAt(fileIn, 0x0A, m_nPlayers, fLoad);
		serializeWordAt(fileIn, 0x0C, m_iX, fLoad);
		serializeWordAt(fileIn, 0x0E, m_iY, fLoad);
		serializeWordAt(fileIn, 0x10, m_nDir, fLoad);
		serializeWordAt(fileIn, 0x12, m_nLevel, fLoad);

		for (UINT i = 0; i < 4; i++) {
			UINT nBasePos = 0x03F0 + 0x31F * i;
			serializeWordAt(fileIn, nBasePos + 0x34, m_p4s[i].nCurHP, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x36, m_p4s[i].nMaxHP, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x38, m_p4s[i].nCurSta, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x3A, m_p4s[i].nMaxSta, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x3C, m_p4s[i].nCurMana, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x3E, m_p4s[i].nMaxMana, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x42, m_p4s[i].nFood, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x44, m_p4s[i].nWater, fLoad);

			serializeByteAt(fileIn, nBasePos + 0x49, m_p4s[i].nCurStr, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x4A, m_p4s[i].nMaxStr, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x4C, m_p4s[i].nCurDex, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x4D, m_p4s[i].nMaxDex, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x4F, m_p4s[i].nCurWiz, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x50, m_p4s[i].nMaxWiz, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x52, m_p4s[i].nCurVit, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x53, m_p4s[i].nMaxVit, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x55, m_p4s[i].nCurAM, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x56, m_p4s[i].nMaxAM, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x58, m_p4s[i].nCurAF, fLoad);
			serializeByteAt(fileIn, nBasePos + 0x59, m_p4s[i].nMaxAF, fLoad);

			serializeWordAt(fileIn, nBasePos + 0x5E, m_p4s[i].nSk1, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x64, m_p4s[i].nSk2, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x6A, m_p4s[i].nSk3, fLoad);
			serializeWordAt(fileIn, nBasePos + 0x70, m_p4s[i].nSk4, fLoad);
		}

		return TRUE;
	CATCH_ALL(e)

	END_CATCH_ALL

	return FALSE;
}

BOOL CDMSmcSrmModDlg::LoadFrom(LPCTSTR pszFileIn)
{
	return Serialize(pszFileIn, TRUE);
}

BOOL CDMSmcSrmModDlg::SaveTo(LPCTSTR pszFileIn)
{
	return Serialize(pszFileIn, FALSE);
}

void TransVar(UINT &x, UINT &y, BOOL fL2R)
{
	if (fL2R)
			y = x;
	else	x = y;
}

void TransVar(UINT &x, CString &y, BOOL fL2R)
{
	if (fL2R) {
		y.Format("%u", x);
	} else {
		x = _ttoi(y);
	}
}

void CDMSmcSrmModDlg::revertPlayer(UINT i, BOOL fRevert)
{
	TransVar(m_p4s[i].nCurHP, m_nCurHP, fRevert);
	TransVar(m_p4s[i].nMaxHP, m_nMaxHP, fRevert);
	TransVar(m_p4s[i].nCurSta, m_nCurSta, fRevert);
	TransVar(m_p4s[i].nMaxSta, m_nMaxSta, fRevert);
	TransVar(m_p4s[i].nCurMana, m_nCurMana, fRevert);
	TransVar(m_p4s[i].nMaxMana, m_nMaxMana, fRevert);
	TransVar(m_p4s[i].nFood, m_nCurFood, fRevert);
	TransVar(m_p4s[i].nWater, m_nCurWater, fRevert);
	TransVar(m_p4s[i].nCurStr, m_nCurStr, fRevert);
	TransVar(m_p4s[i].nMaxStr, m_nMaxStr, fRevert);
	TransVar(m_p4s[i].nCurDex, m_nCurDex, fRevert);
	TransVar(m_p4s[i].nMaxDex, m_nMaxDex, fRevert);
	TransVar(m_p4s[i].nCurWiz, m_nCurWiz, fRevert);
	TransVar(m_p4s[i].nMaxWiz, m_nMaxWiz, fRevert);
	TransVar(m_p4s[i].nCurVit, m_nCurVit, fRevert);
	TransVar(m_p4s[i].nMaxVit, m_nMaxVit, fRevert);
	TransVar(m_p4s[i].nCurAM, m_nCurAntiMajic, fRevert);
	TransVar(m_p4s[i].nMaxAM, m_nMaxAntiMajic, fRevert);
	TransVar(m_p4s[i].nCurAF, m_nCurAntiFire, fRevert);
	TransVar(m_p4s[i].nMaxAF, m_nMaxAntiFire, fRevert);

	TransVar(m_p4s[i].nSk1, m_strSk1, fRevert);
	TransVar(m_p4s[i].nSk2, m_strSk2, fRevert);
	TransVar(m_p4s[i].nSk3, m_strSk3, fRevert);
	TransVar(m_p4s[i].nSk4, m_strSk4, fRevert);
}

void CDMSmcSrmModDlg::OnEditChangeComboLevel() 
{
	// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
	
}

void CDMSmcSrmModDlg::OnSelChangeComboLevel() 
{
	if (!UpdateData()) return;

	m_wndAtlas.SetCurMap(m_nLevel);
}

void CDMSmcSrmModDlg::OnSelChangeMap()
{
	if (!UpdateData()) return;

	CPoint point = m_wndAtlas.GetCursorPos();

	m_iX = point.x;
	m_iY = point.y;

	UpdateData(FALSE);
}

bool CDMSmcSrmModDlg::chkSaveData(CFile &file)
{
	CHAR c[16];

	m_iOffset = 0;
	VERIFY(file.Seek(0x7FF0, CFile::begin) == 0x7FF0);
	if (file.Read(c, 16) == 16 && memcmp(c, "DM SFX SAVE DATA", 16) == 0) return true;

	m_iOffset = 0x80;
	VERIFY(file.Seek(0x0070, CFile::begin) == 0x0070);
	if (file.Read(c, 16) == 16 && memcmp(c, "DM SFX SAVE DATA", 16) == 0) return true;

	return false;
}

void CDMSmcSrmModDlg::serializeByteAt(CFile &file, UINT nPos, UINT &x, BOOL fLoad)
{
	if (fLoad)
		readByteAt(file, m_iOffset + nPos, x);
	else
		writeByteAt(file, m_iOffset + nPos, x);
}

void CDMSmcSrmModDlg::serializeWordAt(CFile &file, UINT nPos, UINT &x, BOOL fLoad)
{
	if (fLoad)
		readWordAt(file, m_iOffset + nPos, x);
	else
		writeWordAt(file, m_iOffset + nPos, x);
}
