SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWizard (C) 1998 by Russ Pillsbury (Windows NT version)|   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************/
// SmaugWizView.cpp : implementation of the CSmaugWizView class

#include	"stdafx.h"
#include	"SmaugWiz.h"

#include	"smaug.h"
#include	"SmaugSocket.h"
#include	"sysdata.h"
#include	"mobiles.h"
#include	"SmaugWizDoc.h"
#include	"autostart.h"
#include	"SmaugWizView.h"

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

/////////////////////////////////////////////////////////////////////////////
// CSmaugWizView

IMPLEMENT_DYNCREATE(CSmaugWizView, CScrollView)

BEGIN_MESSAGE_MAP(CSmaugWizView, CScrollView)
	//{{AFX_MSG_MAP(CSmaugWizView)
	ON_WM_TIMER()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSmaugWizView construction/destruction

CSmaugWizView::CSmaugWizView ()
{
	m_pTimerDlg = NULL;
}

CSmaugWizView::~CSmaugWizView ()
{
}

BOOL CSmaugWizView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CSmaugWizView drawing

void CSmaugWizView::OnDraw(CDC* pDC)
{
	CSmaugWizDoc* pDoc = GetDocument ();
	ASSERT_VALID(pDoc);
	CRect		rectClip;

	if (pDoc->GetLineCount () == 0) then return;

	// The window has been invalidated and needs to be repainted.
	// First, determine the range of rows that need to be displayed.
	int nFirstRow, nLastRow;
	pDC->GetClipBox (&rectClip);	// Get the invalidated region.
	RectLPtoRowRange (rectClip, nFirstRow, nLastRow, TRUE);

	// Draw each row in the invalidated region of the window,
	// or on the printed (previewed) page.
	int		nRow = nFirstRow;
	int		y = m_nRowHeight * nFirstRow;
	while (nRow <= nLastRow) {
		OnDrawRow (pDC, nRow, y);
		++nRow;
		y += m_nRowHeight;
	}
}


void CSmaugWizView::OnDrawRow (CDC* pDC, int Row, int y)
{
	char	*s = GetDocument ()->GetData (Row);
	int		len = strlen (s);
	if (len == 0) then return;

	pDC->TextOut (0, y, s, len);
}

/////////////////////////////////////////////////////////////////////////////
// CSmaugWizView printing

BOOL CSmaugWizView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CSmaugWizView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CSmaugWizView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CSmaugWizView diagnostics

#ifdef _DEBUG
void CSmaugWizView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CSmaugWizView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CSmaugWizDoc* CSmaugWizView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSmaugWizDoc)));
	return (CSmaugWizDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSmaugWizView message handlers

void CSmaugWizView::OnTimer(UINT nIDEvent) 
{
#ifdef n_DEBUG
	// Note I used a convenient flag to trigger the memory dump. By using the config screen
	// to turn on auto-start, the memory dump is triggered each time.
	if (SysData.IsAutoStart ()) {
		newMemState.Checkpoint();
		if (diffMemState.Difference( oldMemState, newMemState)) {
			TRACE ("Memory leaked!\n");
			diffMemState.DumpStatistics ();
			oldMemState.DumpAllObjectsSince ();
		}
		SysData.SetAutoStart (FALSE);
	}
#endif
	if (nIDEvent == 1) then {
		CClientDC dc (this);
		GetDocument ()->GameLoop (&dc);

		if (bSmaugDown) {
			KillTimer (1);
			BOOL	bAutoReboot =
						SysData.IsAutoReboot () && gpDoc->IsReboot ();
			int		RebootDelay = SysData.GetRebootDelay ();
			ClearDatabase ();
			gpDoc->m_pLog->Close ();
			delete gpDoc->m_pControl;
			gpDoc->m_pControl = NULL;

//			if (! bAutoReboot)
//				ResendExitMsg ();

			// Start a timer to restart mud
			if (bAutoReboot) {
				SetTimer (2, 1000 * RebootDelay, NULL);
			}
			return;
		}
	}

	if (nIDEvent == 2) then {
		KillTimer (2);
		AfxGetMainWnd ()->PostMessage (WM_COMMAND, ID_FILE_START);
	}

	if (nIDEvent == 3) then {
		if (! m_pTimerDlg) {
			m_pTimerDlg = new CAutoStart (this);
			m_pTimerDlg->Create ();
			m_pTimerDlg->ShowWindow (SW_SHOW);
		}
		if (m_pTimerDlg->m_bCancel) {
			KillTimer (3);
			m_pTimerDlg->DestroyWindow ();
			m_pTimerDlg = NULL;
			return;
		}
		if (m_pTimerDlg->m_bStartNow) then gpDoc->m_TimeTilStart = 1;

		if (--gpDoc->m_TimeTilStart) {
			m_pTimerDlg->m_Time = gpDoc->m_TimeTilStart;
			m_pTimerDlg->UpdateData (FALSE);
		} else {
			KillTimer (3);
			m_pTimerDlg->DestroyWindow ();
			m_pTimerDlg = NULL;
			AfxGetMainWnd ()->PostMessage (WM_COMMAND, ID_FILE_START);
		}
	}

	CScrollView::OnTimer(nIDEvent);
}


void CSmaugWizView::OnInitialUpdate () 
{
	m_nPrevRowCount = GetDocument ()->GetLineCount();

	SetScrollSizes (MM_TEXT, CSize (620,900));
	CScrollView::OnInitialUpdate ();
}


void CSmaugWizView::OnUpdate (CView* pSender, LPARAM lHint, CObject* pHint) 
{
	int	InvalidRow = lHint;

	int nRowCount = GetDocument ()->GetLineCount ();
	// If the number of rows has changed, then adjust the scrolling range.
	if (nRowCount != m_nPrevRowCount) {
		UpdateScrollSizes ();
		m_nPrevRowCount = nRowCount;
	}
	
	CClientDC dc (this);
	OnPrepareDC (&dc);
	CalculateRowMetrics (&dc);

	// Determine the range of the rows that are currently fully visible
	// in the window.  We want to do discrete scrolling by so that
	// the next or previous row is always fully visible.
	int nFirstRow, nLastRow;
	CRect rectClient;
	GetClientRect (&rectClient);
	dc.DPtoLP (&rectClient);
	RectLPtoRowRange (rectClient, nFirstRow, nLastRow, FALSE);

	// If necessary, scroll the window so the newly selected row is
	// visible.
	POINT pt;
	pt.x = 0;
	BOOL bNeedToScroll = TRUE;
	if (InvalidRow < nFirstRow)
	{
		// The newly selected row is above those currently visible
		// in the window.  Scroll so the newly selected row is at the
		// very top of the window.  The last row in the window might
		// be only partially visible.
		pt.y = RowToYPos (InvalidRow);
	}
	else if (InvalidRow > nLastRow)
	{
		// The newly selected row is below those currently visible
		// in the window.  Scroll so the newly selected row is at the
		// very bottom of the window.  The first row in the window might
		// be only partially visible.
		pt.y = max (0, RowToYPos (InvalidRow+1) - rectClient.Height ());
	}
	else bNeedToScroll = FALSE;

	if (bNeedToScroll) {
		// Scrolling will cause the newly selected row to be
		// redrawn in the invalidated area of the window.
		ScrollToDevicePosition (pt);

		// Need to prepare the DC again because
		// ScrollToDevicePosition () will have changed the viewport
		// origin.  The DC is used some more below.
		OnPrepareDC (&dc);
		CalculateRowMetrics (&dc);
	}

	if (InvalidRow < MAX_LINES) then InvalidateRect (NULL);
	else {
		CRect rectInvalid = RowToWndRect (&dc, InvalidRow);
		InvalidateRect (&rectInvalid);
	}
}


void CSmaugWizView::UpdateScrollSizes ()
{
	CSmaugWizDoc* pDoc = GetDocument ();
	ASSERT_VALID (pDoc);
	// UpdateScrollSizes () is called when it is necessary to adjust the
	// scrolling range or page/line sizes.  There are two occassions
	// where this is necessary:  (1) when a new row is added-- see
	// Update ()-- and (2) when the window size changes-- see OnSize ().

	CRect rectClient;
	GetClientRect (&rectClient);

	CClientDC dc (this);
	CalculateRowMetrics (&dc);

	// The vert scrolling range is the total display height of all
	// of the rows.
	CSize sizeTotal (m_nRowWidth, m_nRowHeight * pDoc->GetLineCount ());

	// The vertical per-page scrolling distance is equal to the
	// how many rows can be displayed in the current window, less
	// one row for paging overlap.
	CSize sizePage(m_nRowWidth/5,
			max(m_nRowHeight,
				((rectClient.bottom/m_nRowHeight)-1)*m_nRowHeight));

	// The vertical per-line scrolling distance is equal to the
		// height of the row.
	CSize sizeLine(m_nRowWidth/20, m_nRowHeight);

	SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
}


void CSmaugWizView::GetRowWidthHeight (CDC* pDC, int& Width, int& Height)
{
	TEXTMETRIC tm;
	pDC->GetTextMetrics (&tm);
	Width = tm.tmAveCharWidth * LINE_LEN;
	Height = tm.tmHeight;
}


CRect CSmaugWizView::RowToWndRect (CDC* pDC, int nRow)
{
	int nHorzRes = pDC->GetDeviceCaps (HORZRES);;
	CRect rect (0, nRow * m_nRowHeight, nHorzRes, (nRow + 1) * m_nRowHeight);
	pDC->LPtoDP (&rect);
	return rect;
}


void CSmaugWizView::RectLPtoRowRange(const CRect& rect, int& FirstRow,
									 int& LastRow,
									 BOOL bIncludePartiallyShownRows)
{
	int nRounding = bIncludePartiallyShownRows ? 0 : (m_nRowHeight - 1);
	FirstRow = (rect.top + nRounding) / m_nRowHeight;
	LastRow = min ((rect.bottom - nRounding) / m_nRowHeight,
		GetDocument ()->GetLineCount () - 1);
}


void CSmaugWizView::OnSize (UINT nType, int cx, int cy) 
{
	UpdateScrollSizes ();
	CScrollView::OnSize (nType, cx, cy);
}

BOOL CSmaugWizView::OnCommand(WPARAM wParam, LPARAM lParam) 
{
//	UINT nID = LOWORD(wParam);
//	if (nID == WM_BOOT_SMAUG) then {
//		if (GetDocument ()->BootAndStart ()) then
//			SetTimer (1, 1000 / PULSE_PER_SECOND, NULL);
//		return TRUE;
//	}
	
	return CScrollView::OnCommand(wParam, lParam);
}