/****************************************************************************
* [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);
}