Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

559 lines
14 KiB

/***************************************************************************/
/** Microsoft Windows **/
/** Copyright(c) Microsoft Corp., 1991, 1992 **/
/***************************************************************************/
/****************************************************************************
human.cpp
Aug 92, JimH
May 93, JimH chico port
local_human and remote_human member functions
****************************************************************************/
#include "hearts.h"
#include "main.h" // friendly access
#include "resource.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h> // abs() prototype
static CRect rectCard; // used in timer callback
// declare static members
BOOL local_human::bTimerOn;
CString local_human::m_StatusText;
/****************************************************************************
human constructor -- abstract class
****************************************************************************/
human::human(int n, int pos) : player(n, pos)
{
}
/****************************************************************************
local_human::local_human()
This is the constructor that initializes player::hWnd and player::hInst.
It also creates the stretch bitmap that covers a card plus its popped
height extension.
****************************************************************************/
local_human::local_human(int n) : human(n, 0)
{
m_pStatusWnd = new CStatusBarCtrl();
m_StatusText.LoadString(IDS_INTRO);
CClientDC dc(::pMainWnd);
m_pStatusWnd->Create(WS_CHILD|WS_VISIBLE|CCS_BOTTOM, CRect(), ::pMainWnd, 0);
m_pStatusWnd->SetSimple();
UpdateStatus();
bTimerOn = FALSE;
if (!m_bmStretchCard.CreateCompatibleBitmap(&dc, card::dxCrd,
card::dyCrd + POPSPACING))
{
::pMainWnd->FatalError(IDS_MEMORY);
return;
}
}
/****************************************************************************
local_human destructor
****************************************************************************/
local_human::~local_human()
{
m_bmStretchCard.DeleteObject();
delete m_pStatusWnd;
m_pStatusWnd = NULL;
}
/****************************************************************************
local_human::Draw()
This virtual function draws selected cards in the popped up position.
ALL is not used for slot in this variant.
****************************************************************************/
void local_human::Draw(CDC &dc, BOOL bCheating, SLOT slot)
{
DisplayName(dc);
SLOT start = (slot == ALL ? 0 : slot);
SLOT stop = (slot == ALL ? MAXSLOT : slot+1);
SLOT playedslot = EMPTY; // must draw cards in play last for EGA
for (SLOT s = start; s < stop; s++)
{
if (cd[s].IsPlayed())
playedslot = s;
else
cd[s].PopDraw(dc); // pop up selected cards
}
if (playedslot != EMPTY)
cd[playedslot].Draw(dc);
}
/****************************************************************************
local_human::PopCard()
handles mouse button selection of card to pass
****************************************************************************/
void local_human::PopCard(CBrush &brush, int x, int y)
{
SLOT s = XYToCard(x, y);
if (s == EMPTY)
return;
// count selected cards
int c = 0;
for (int i = 0; i < MAXSLOT; i++)
if (cd[i].IsSelected())
c++;
if (cd[s].IsSelected() && (c == 3))
{
::pMainWnd->PostMessage(WM_COMMAND, IDM_HIDEBUTTON);
}
else if (!cd[s].IsSelected())
{
if (c == 3) // only allow three selections
return;
else if (c == 2)
::pMainWnd->PostMessage(WM_COMMAND, IDM_SHOWBUTTON);
}
// toggle selection
BOOL bSelected = cd[s].IsSelected();
cd[s].Select(!bSelected);
CClientDC dc(::pMainWnd);
#ifdef USE_MIRRORING
SetLayout(dc.m_hDC, 0);
SetLayout(dc.m_hAttribDC, 0);
#endif
CDC memDC;
memDC.CreateCompatibleDC(&dc);
memDC.SelectObject(&m_bmStretchCard);
memDC.SelectObject(&brush);
memDC.PatBlt(0, 0, card::dxCrd, card::dyCrd + POPSPACING, PATCOPY);
for (i = 0; i < MAXSLOT; i++)
{
if (abs(i - s) <= (card::dxCrd / HORZSPACING))
{
cd[i].Draw(memDC, // cdc
(i - s) * HORZSPACING, // x
cd[i].IsSelected() ? 0 : POPSPACING, // y
FACEUP, // mode
FALSE); // update loc?
}
}
dc.BitBlt(loc.x + (HORZSPACING * s), loc.y - POPSPACING,
card::dxCrd, card::dyCrd + POPSPACING,
&memDC, 0, 0, SRCCOPY);
}
/****************************************************************************
local_human::PlayCard()
handles mouse button selection of card to play
and ensures move is legal.
PlayCard starts a timer that calls StartTimer() which calls TimerBadMove().
Think of it as one long function with a timer delay half way through.
****************************************************************************/
BOOL local_human::PlayCard(int x, int y, handinfotype &h, BOOL bCheating,
BOOL bFlash)
{
SLOT s = XYToCard(x, y);
if (s == EMPTY)
return FALSE;
card *cardled = h.cardplayed[h.playerled];
BOOL bFirstTrick = (cardled != NULL && cardled->ID() == TWOCLUBS);
/* check if selected card is valid */
if (h.playerled == id) // if local human is leading...
{
if (cd[s].ID() != TWOCLUBS)
{
for (int i = 0; i < MAXSLOT; i++) // is there a two of clubs?
{
if ((i != s) && (cd[i].ID() == TWOCLUBS))
{
UpdateStatus(IDS_LEAD2C);
if (bFlash)
StartTimer(cd[s]);
return FALSE;
}
}
}
if ((cd[s].Suit() == HEARTS) && (!h.bHeartsBroken)) // if hearts led
{
for (int i = 0; i < MAXSLOT; i++) // are there any non-hearts?
{
if ((!cd[i].IsEmpty()) && (cd[i].Suit() != HEARTS))
{
UpdateStatus(IDS_LEADHEARTS);
if (bFlash)
StartTimer(cd[s]);
return FALSE;
}
}
}
}
// if not following suit
else if (cardled != NULL && (cd[s].Suit() != cardled->Suit()))
{
// make sure we're following suit if possible
for (int i = 0; i < MAXSLOT; i++)
{
if ((!cd[i].IsEmpty()) && (cd[i].Suit()==cardled->Suit()))
{
CString s1, s2;
s1.LoadString(IDS_BADMOVE);
s2.LoadString(IDS_SUIT0+cardled->Suit());
TCHAR string[80];
wsprintf(string, s1, s2);
if (bFlash)
{
UpdateStatus(string);
StartTimer(cd[s]);
}
return FALSE;
}
}
// make sure we're not trying to break the First Blood rule
if (bFirstTrick && ::pMainWnd->IsFirstBloodEnforced())
{
BOOL bPointCard =
(cd[s].Suit() == HEARTS || cd[s].ID() == BLACKLADY);
BOOL bOthersAvailable = FALSE;
for (int i = 0; i < MAXSLOT; i++)
if ((!cd[i].IsEmpty()) && (cd[i].Suit() != HEARTS))
if (cd[i].ID() != BLACKLADY)
bOthersAvailable = TRUE;
if (bPointCard && bOthersAvailable)
{
UpdateStatus(IDS_BADBLOOD);
if (bFlash)
StartTimer(cd[s]);
return FALSE;
}
}
}
SetMode(WAITING);
cd[s].Play();
h.cardplayed[id] = &(cd[s]);
::move.playerid = id;
::move.cardid = cd[s].ID();
::move.playerled = h.playerled;
::move.turn = h.turn;
::pMainWnd->OnRef();
return TRUE;
}
void local_human::StartTimer(card &c)
{
CClientDC dc(::pMainWnd);
#ifdef USE_MIRRORING
SetLayout(dc.m_hDC, 0);
SetLayout(dc.m_hAttribDC, 0);
#endif
c.Draw(dc, HILITE); // flash
c.GetRect(rectCard);
if (::pMainWnd->SetTimer(1, 250, TimerBadMove))
{
bTimerOn = TRUE;
}
else
{
bTimerOn = FALSE;
::pMainWnd->InvalidateRect(&rectCard, FALSE);
}
}
// MFC2 changes same as SetTimer in main2.cpp
#if defined (MFC1)
UINT FAR PASCAL EXPORT
TimerBadMove(HWND hWnd, UINT nMsg, int nIDEvent, DWORD dwTime)
{
::KillTimer(hWnd, 1);
local_human::bTimerOn = FALSE;
::InvalidateRect(hWnd, &rectCard, FALSE);
return 0;
}
#else
void FAR PASCAL EXPORT
TimerBadMove(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime)
{
::KillTimer(hWnd, 1);
local_human::bTimerOn = FALSE;
#ifdef USE_MIRRORING
CRect rect;
int i;
DWORD ProcessDefaultLayout;
if (GetProcessDefaultLayout(&ProcessDefaultLayout))
if (ProcessDefaultLayout == LAYOUT_RTL)
{
GetClientRect(hWnd, &rect);
rectCard.left = abs(rect.right - rect.left) - rectCard.left;
rectCard.right = abs(rect.right - rect.left) - rectCard.right;
i = rectCard.left;
rectCard.left = rectCard.right;
rectCard.right = i;
}
#endif
::InvalidateRect(hWnd, &rectCard, FALSE);
}
#endif
/****************************************************************************
local_human::XYToCard()
returns a card slot number (or EMPTY) given a mouse location
****************************************************************************/
int local_human::XYToCard(int x, int y)
{
// check that we are in the right general area on the screen
if (y < (loc.y - POPSPACING))
return EMPTY;
if (y > (loc.y + card::dyCrd))
return EMPTY;
if (x < loc.x)
return EMPTY;
if (x > (loc.x + (12 * HORZSPACING) + card::dxCrd))
return EMPTY;
// Take first stab at card selected.
SLOT s = (x - loc.x) / HORZSPACING;
if (s > 12)
s = 12;
// If the click is ABOVE the top of the normal card location,
// check to see if this is a selected card.
if (y < loc.y)
{
// If the card is bSelected, then we have it. If not, it could
// be overhanging other cards.
if (!cd[s].IsSelected())
{
for (;;)
{
if (s == 0)
return EMPTY;
s--;
// if this card doesn't extend as far as x, give up
if ((loc.x + (s * HORZSPACING) + card::dxCrd) < x)
return EMPTY;
// if this card is selected, we've got it
if (cd[s].IsSelected())
break;
}
}
}
// a similar check is used to make sure we pick a card not yet played
if (!cd[s].IsInHand())
{
for (;;)
{
if (s == 0)
return EMPTY;
s--;
// if this card doesn't extend as far as x, give up
if ((loc.x + (s * HORZSPACING) + card::dxCrd) < x)
return EMPTY;
// if this card is selected, we've got it
if (cd[s].IsInHand())
break;
}
}
return s;
}
/****************************************************************************
local_human::SelectCardsToPass()
This virtual function allows mouse clicks to mean select a card to play.
****************************************************************************/
void local_human::SelectCardsToPass()
{
SetMode(SELECTING);
}
/****************************************************************************
local_human::SelectCardToPlay
Computer versions of this virtual function actually do the card selection.
This local_human version marks the player as ready to select a card to
play with the mouse, and updates the status to reflect this.
****************************************************************************/
void local_human::SelectCardToPlay(handinfotype &h, BOOL bCheating)
{
SetMode(PLAYING);
UpdateStatus(IDS_GO);
}
/****************************************************************************
local_human::UpdateStatus
The status bar can be updated either by manually filling m_StatusText
or by passing a string resource id.
****************************************************************************/
void local_human::UpdateStatus(void)
{
m_pStatusWnd->SetText(m_StatusText, 255, 0);
}
void local_human::UpdateStatus(int stringid)
{
status = stringid;
m_StatusText.LoadString(stringid);
UpdateStatus();
}
void local_human::UpdateStatus(const TCHAR *string)
{
m_StatusText = string;
UpdateStatus();
}
/****************************************************************************
local_human::ReceiveSelectedCards
The parameter c[] is an array of three cards being passed from another
player.
****************************************************************************/
void local_human::ReceiveSelectedCards(int c[])
{
for (int i = 0, j = 0; j < 3; i++)
{
if (cd[i].IsSelected())
cd[i].SetID(c[j++]);
ASSERT(i < MAXSLOT);
}
SetMode(ACCEPTING);
UpdateStatus(IDS_ACCEPT);
}
/****************************************************************************
local_human::WaitMessage()
Makes and shows the "Waiting for %s to move..." message
****************************************************************************/
void local_human::WaitMessage(const TCHAR *name)
{
TCHAR buf[100];
CString s;
s.LoadString(IDS_WAIT);
wsprintf(buf, s, name);
UpdateStatus(buf);
}