SCORE.CPP
//--------------------------------------------------------------------------- 
// Score.cpp 
//--------------------------------------------------------------------------- 
// Score object to track score, # lives, level. 
//--------------------------------------------------------------------------- 
// (C) Copyright 1995-1997 by Microsoft Corporation.  All rights reserved. 
// 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF  
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO  
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A  
// PARTICULAR PURPOSE. 
//--------------------------------------------------------------------------- 
 
#include "Main.h" 
#pragma hdrstop 
#include "Score.h" 
#include "Spr.h" 
#include "Game.h" 
extern CGame *g_pgame; 
 
 
//--------------------------------------------------------------------------- 
// DEBUG info 
//--------------------------------------------------------------------------- 
SZTHISFILE 
 
 
//--------------------------------------------------------------------------- 
// Initialize score stuff 
//--------------------------------------------------------------------------- 
HRESULT CScore::s_hr = E_FAIL; 
 
HRESULT CScore::CreateScore 
( 
  HINSTANCE hinst,          // Needed to load bitmaps 
  HWND      hwnd,           // hwnd on which to draw the Score, Level, # Lives 
  HWND      hwndPS,         // hwnd of PlaySurface 
  HWND      hwndStat,       // hwnd of Status Bar 
  long      scoreFirst1Up,  // Score to first new life 
  long      scoreSecond1Up, // Score to 2nd new life 
  long      dscoreNext1Up,  // Score to next new life 
  int       cship,          // Number lives to start 
  IDBMP     idbmpShip,      // Bitmap for display of # lives 
  IDBMP     idbmpPlus,      // Bitmap for "+" when out of room for # lives 
  CScore  **ppscoreOut      // Return value: new score object 
) 
{ 
  // Initialize output parameters 
  *ppscoreOut = NULL; 
 
  // Validate required args, etc. 
  if (!idbmpShip || !hwnd) 
    return E_INVALIDARG; 
 
  *ppscoreOut = new CScore(hinst, hwnd, hwndPS, hwndStat, scoreFirst1Up, scoreSecond1Up, dscoreNext1Up, cship, idbmpShip, idbmpPlus); 
  if (!ppscoreOut) 
    return E_OUTOFMEMORY; 
  if (s_hr) 
    { 
    delete *ppscoreOut; 
    return s_hr; 
    } 
 
  return S_OK; 
} 
 
 
//--------------------------------------------------------------------------- 
// Initialize score stuff 
//--------------------------------------------------------------------------- 
CScore::CScore 
( 
  HINSTANCE hinst,          // Needed to load bitmaps 
  HWND      hwnd,           // hwnd on which to draw the Score, Level, # Lives 
  HWND      hwndPS,         // hwnd of PlaySurface 
  HWND      hwndStat,       // hwnd of Status Bar 
  long      scoreFirst1Up,  // Score to first new life 
  long      scoreSecond1Up, // Score to 2nd new life 
  long      dscoreNext1Up,  // Score to next new life 
  int       cshipStart,     // Number lives to start 
  IDBMP     idbmpShip,      // Bitmap for display of # lives 
  IDBMP     idbmpPlus       // Bitmap for "+" when out of room for # lives 
) 
{ 
  BITMAP bmp; 
  RECT   rectStat; 
 
  INIT_SIGNATURE(SIG_Score); 
 
  // Assume success 
  s_hr = S_OK; 
 
  // Assume reasonable default values, if not supplied 
  m_hinst          = hinst; 
  m_hwnd           = hwnd; 
  m_hwndStat       = hwndStat; 
  m_hwndPS         = hwndPS; 
  m_scoreFirst1Up  = scoreFirst1Up  ? scoreFirst1Up : 0x7fffffff; 
  m_scoreSecond1Up = scoreSecond1Up ? scoreFirst1Up : 0x7fffffff; 
  m_dscoreNext1Up  = dscoreNext1Up  ? dscoreNext1Up : 0x7fffffff; 
  m_cshipStart     = cshipStart; 
 
  // Init rest of class 
  m_hbmpShip  = NULL; 
  m_hbmpPlus  = NULL; 
  m_cyMax     = 0; 
  m_cxShip    = 0; 
  m_cyShip    = 0; 
  m_cxPlus    = 0; 
  m_cyPlus    = 0; 
  // m_scoreNext1Up = m_scoreFirst1Up;    // Handled by NewGame() 
  // m_score        = 0;                  // Handled by NewGame() 
  // m_cship        = m_cshipStart;       // Handled by NewGame() 
  // m_lvl          = 0;                  // Handled by NewGame() 
  // m_rectScore    = 0;                  // Handled below 
  // m_rectShip     = 0;                  // Handled below 
  // m_rectLvl      = 0;                  // Handled below 
 
  // Finish initing the score object 
  this->NewGame(); 
  ASSERT(m_scoreNext1Up == m_scoreFirst1Up, "NewGame() not initing all"); 
  ASSERT(!m_score, "NewGame() not initing all"); 
  ASSERT(m_cship == cshipStart, "NewGame() not initing all"); 
  ASSERT(!m_lvl, "NewGame() not initing all"); 
 
  // Load the bmp for the display of lives 
  m_hbmpShip = LoadBitmap(hinst, MAKEINTRESOURCE(idbmpShip)); 
  if (!m_hbmpShip) 
    { 
    s_hr = E_FAIL; 
    return; 
    } 
  GetObject(m_hbmpShip, sizeof(bmp), (HGDIOBJ)&bmp); 
  m_cxPlus = m_cxShip = bmp.bmWidth; 
  m_cyPlus = m_cyShip = m_cyMax = bmp.bmHeight; 
 
  // Load the bmp of the "+" for the display of lives 
  if (idbmpPlus) 
    { 
    m_hbmpPlus = LoadBitmap(hinst, MAKEINTRESOURCE(idbmpPlus)); 
    if (!m_hbmpPlus) 
      { 
      s_hr = E_FAIL; 
      return; 
      } 
    GetObject(m_hbmpPlus, sizeof(bmp), (HGDIOBJ)&bmp); 
    m_cxPlus = bmp.bmWidth; 
    m_cyPlus = bmp.bmHeight; 
    if (m_cyPlus > m_cyMax) 
      m_cyMax = m_cyPlus; 
    } 
 
  // Calc height of Text. 
  // HACK: Cheat and use DrawText() with a "|" instead of getting TextMetrics... 
  rectStat.top = 0; 
  DrawText(GetDC(hwnd), "|", 1, &rectStat, DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_CALCRECT); 
  m_cyStat = rectStat.bottom; 
  if (rectStat.bottom > m_cyMax) 
    m_cyMax = rectStat.bottom; 
 
  // Place PlaySurface correctly 
  this->Size(372, 282); 
} 
 
 
//--------------------------------------------------------------------------- 
// Given the size of the PlaySurface, calculate the size of the Dlg & other 
// components. 
//--------------------------------------------------------------------------- 
void CScore::Size 
( 
  int cx, 
  int cy 
) 
{ 
  RECT rect, rectCli; 
 
#define cBRD  (6) 
  GetWindowRect(m_hwnd, &rect); 
  GetClientRect(m_hwnd, &rectCli); 
  ClientToScreen(m_hwnd, (LPPOINT)&rectCli); 
  ClientToScreen(m_hwnd, (LPPOINT)&rectCli.right); 
  MoveWindow(m_hwnd,     rect.left, 
                         rect.top, 
                         cx + (2 * cBRD) + (rect.right - rect.left) - (rectCli.right - rectCli.left), 
                         cy + (3 * cBRD + m_cyMax + m_cyStat) + (rect.bottom - rect.top) - (rectCli.bottom - rectCli.top), 
                         TRUE); 
  GetClientRect(m_hwnd, &rect); 
  MoveWindow(m_hwndStat, cBRD, 
                         rect.bottom - (m_cyStat + cBRD), 
                         rect.right  - (2 * cBRD), 
                         m_cyStat, TRUE); 
  MoveWindow(m_hwndPS,   cBRD, 
                         cBRD + m_cyMax, 
                         rect.right  - (2 * cBRD), 
                         rect.bottom - (3 * cBRD + m_cyMax + m_cyStat), TRUE); 
  GetWindowRect(m_hwndPS, &rect); 
  ScreenToClient(m_hwnd, (LPPOINT)&rect); 
  ScreenToClient(m_hwnd, (LPPOINT)&rect.right); 
  rect.top    = 1; 
  rect.bottom = m_cyMax + 4; 
  m_rectScore = rect; 
  m_rectShip  = rect; 
  m_rectLvl   = rect; 
  m_rectShip.right = m_rectLvl.left   = rect.left +  (rect.right - rect.left) / 3; 
  m_rectLvl.right  = m_rectScore.left = rect.left + ((rect.right - rect.left) / 3 * 2); 
  GetClientRect(m_hwndPS, &rect); 
  g_pgame->m_pdisp->m_cx = rect.right  - rect.left; 
  g_pgame->m_pdisp->m_cy = rect.bottom - rect.top; 
  InvalidateRect(m_hwnd,   NULL, TRUE); 
  InvalidateRect(m_hwndPS, NULL, TRUE); 
} 
 
 
//--------------------------------------------------------------------------- 
// Terminate score stuff 
//--------------------------------------------------------------------------- 
CScore::~CScore 
( 
  void 
) 
{ 
  CHECK_SIGNATURE(SIG_Score); 
 
  if (m_hbmpShip) 
    DeleteObject((HGDIOBJ)m_hbmpShip); 
  if (m_hbmpPlus) 
    DeleteObject((HGDIOBJ)m_hbmpPlus); 
 
  DESTROY_SIGNATURE(SIG_Score); 
} 
 
 
//--------------------------------------------------------------------------- 
// Re-initialize score stuff for new game 
//--------------------------------------------------------------------------- 
void CScore::NewGame 
( 
  void 
) 
{ 
  m_scoreNext1Up = m_scoreFirst1Up; 
  m_score        = 0; 
  m_cship        = m_cshipStart; 
  m_lvl          = 0; 
 
  InvalidateRect(m_hwnd, NULL, TRUE); 
} 
 
 
//--------------------------------------------------------------------------- 
// Paint score stuff: # 1Ups, current level, score 
//--------------------------------------------------------------------------- 
void CScore::Paint 
( 
  HDC hdc 
) 
{ 
  char rgch[100]; 
  int x, y; 
  int i; 
  extern HDC     g_hdcMem; 
  extern HBITMAP g_hbmpStock; 
 
  SelectObject(g_hdcMem, m_hbmpShip); 
  x = m_rectShip.left; 
  y = m_rectShip.top + ((m_rectShip.bottom - m_rectShip.top - m_cyShip) >> 1); 
 
  // Draw the 1Ups w/a "+", if necessary 
  for (i=1; i<m_cship; i++) 
    { 
    BitBlt(hdc, x, y, m_cxShip, m_cyShip, g_hdcMem, 0, 0, SRCCOPY); 
    x += m_cxShip + (m_cxShip >> 2); 
 
    // If we only have more 1Ups, but only room for the "+", draw the "+" 
    if (x + m_cxShip + m_cxPlus > m_rectShip.right && m_hbmpPlus && i+1<m_cship) 
      { 
      y = m_rectShip.top + ((m_rectShip.bottom - m_rectShip.top - m_cyPlus) >> 1); 
      SelectObject(g_hdcMem, m_hbmpPlus); 
      BitBlt(hdc, x, y, m_cxPlus, m_cyPlus, g_hdcMem, 0, 0, SRCCOPY); 
      break; 
      } 
    } 
  SelectObject(g_hdcMem, g_hbmpStock); 
 
  SetBkMode(hdc, TRANSPARENT); 
  wsprintf(rgch, "%ld", m_score); 
  DrawText(hdc, rgch, -1, &m_rectScore, DT_RIGHT|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER); 
 
  wsprintf(rgch, "%d", m_lvl); 
  DrawText(hdc, rgch, -1, &m_rectLvl,   DT_CENTER|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER); 
} 
 
 
//--------------------------------------------------------------------------- 
// Change the score by the delta d. 
//--------------------------------------------------------------------------- 
void CScore::Add 
( 
  long d      // Change the score by this amount (signed) 
) 
{ 
  m_score += d; 
  if (m_score < 0) 
    m_score = 0; 
  if (m_score >= m_scoreNext1Up) 
    { 
    if (m_score > m_scoreSecond1Up) 
      m_scoreNext1Up += m_dscoreNext1Up; 
    else 
      m_scoreNext1Up = m_scoreSecond1Up; 
    m_cship++; 
    InvalidateRect(m_hwnd, &m_rectShip, TRUE); 
    g_pgame->m_pgameoa->FireNewShip(); 
    } 
 
  InvalidateRect(m_hwnd, &m_rectScore, TRUE); 
} 
 
 
//--------------------------------------------------------------------------- 
// Called when pausing or unpausing 
//--------------------------------------------------------------------------- 
void CScore::SetStatusText 
( 
  const char *pszText 
) 
{ 
  SetWindowText(m_hwndStat, pszText); 
} 
 
//--- EOF -------------------------------------------------------------------