GAMEOA.CPP

//--------------------------------------------------------------------------- 
// GameOA.cpp
//---------------------------------------------------------------------------
// Sample spr program, OLE Automation implementation
//---------------------------------------------------------------------------
// (C) Copyright 1992-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 "Game.h"
#include "App.h"
#include "Spr.h"
#include "Score.h"
#include "DispIDs.h"
#include <math.h>


//---------------------------------------------------------------------------
// DEBUG info
//---------------------------------------------------------------------------
SZTHISFILE


//---------------------------------------------------------------------------
// Various Globals
//---------------------------------------------------------------------------
extern CGame *g_pgame;
ITypeInfo *g_ptinfoClsGameOA = NULL;
ITypeInfo *g_ptinfoIntGameOA = NULL;



//***************************************************************************
// Constructor / Destructor
//***************************************************************************

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
CGameOA::CGameOA
(
CGame *pgame
)
{
m_pgame = pgame;
m_pdispBaseObject = NULL;
}



//***************************************************************************
// Fire IGameEvents Events
//***************************************************************************

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireNewGame
(
void
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_NewGame, NULL, 0);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireNewLevel
(
void
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_NewLevel, NULL, 0);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireNewShip
(
void
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_NewShip, NULL, 0);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireCollide
(
CSprite *psprLowId,
CSprite *psprHighId,
int maskCollide
)
{
IDispatch **ppdisp = g_pgame->m_pgameoa->m_cp.m_rgpdisp;
VARIANTARG var[3];

VariantInit(&var[2]);
var[2].vt = VT_DISPATCH;
var[2].pdispVal = psprLowId->GetDispatch();
psprLowId->AddRef();
VariantInit(&var[1]);
var[1].vt = VT_DISPATCH;
var[1].pdispVal = psprHighId->GetDispatch();
psprHighId->AddRef();
VariantInit(&var[0]);
var[0].vt = VT_I4;
var[0].lVal = maskCollide;

for (; ppdisp < &g_pgame->m_pgameoa->m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_Collide, var, 3);

psprLowId->Release(); // For var[2].pdispVal
psprHighId->Release(); // For var[1].pdispVal
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireTick
(
void
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_Tick, NULL, 0);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireKeyDown
(
int vk
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;
VARIANTARG var[2];

VariantInit(&var[0]);
var[0].vt = VT_I4;
var[0].lVal = vk;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_KeyDown, var, 1);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireKeyPress
(
int ascii
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;
VARIANTARG var[1];

VariantInit(&var[0]);
var[0].vt = VT_I4;
var[0].lVal = ascii;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_KeyPress, var, 1);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireKeyUp
(
int vk
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;
VARIANTARG var[2];

VariantInit(&var[0]);
var[0].vt = VT_I4;
var[0].lVal = vk;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_KeyUp, var, 1);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireMouseMove
(
int x,
int y,
long mk
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;
VARIANTARG var[4];

VariantInit(&var[3]);
var[3].vt = VT_I4;
var[3].lVal = (mk & MK_SHIFT ? 1 : 0) |
(mk & MK_CONTROL ? 2 : 0);
VariantInit(&var[2]);
var[2].vt = VT_I4;
var[2].lVal = (mk & MK_LBUTTON ? 1 : 0) |
(mk & MK_RBUTTON ? 2 : 0) |
(mk & MK_MBUTTON ? 4 : 0);
VariantInit(&var[1]);
var[1].vt = VT_I4;
var[1].lVal = x;
VariantInit(&var[0]);
var[0].vt = VT_I4;
var[0].lVal = y;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_MouseMove, var, 4);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireMouseDown
(
int x,
int y,
long mk,
long button
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;
VARIANTARG var[4];

VariantInit(&var[3]);
var[3].vt = VT_I4;
var[3].lVal = (mk & MK_SHIFT ? 1 : 0) |
(mk & MK_CONTROL ? 2 : 0);
VariantInit(&var[2]);
var[2].vt = VT_I4;
var[2].lVal = (button & MK_LBUTTON ? 1 : 0) |
(button & MK_RBUTTON ? 2 : 0) |
(button & MK_MBUTTON ? 4 : 0);
VariantInit(&var[1]);
var[1].vt = VT_I4;
var[1].lVal = x;
VariantInit(&var[0]);
var[0].vt = VT_I4;
var[0].lVal = y;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_MouseDown, var, 4);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::FireMouseUp
(
int x,
int y,
long mk,
long button
)
{
IDispatch **ppdisp = m_cp.m_rgpdisp;
VARIANTARG var[4];

VariantInit(&var[3]);
var[3].vt = VT_I4;
var[3].lVal = (mk & MK_SHIFT ? 1 : 0) |
(mk & MK_CONTROL ? 2 : 0);
VariantInit(&var[2]);
var[2].vt = VT_I4;
var[2].lVal = (button & MK_LBUTTON ? 1 : 0) |
(button & MK_RBUTTON ? 2 : 0) |
(button & MK_MBUTTON ? 4 : 0);
VariantInit(&var[1]);
var[1].vt = VT_I4;
var[1].lVal = x;
VariantInit(&var[0]);
var[0].vt = VT_I4;
var[0].lVal = y;

for (; ppdisp < &m_cp.m_rgpdisp[GAME_cADVISE]; ppdisp++)
if (*ppdisp)
InvokeEvent(*ppdisp, DISPID_GameEvents_MouseUp, var, 4);
}


//***************************************************************************
// IGame Interface
//***************************************************************************

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Caption
(
BSTR* pRet
)
{
if (!pRet)
return E_INVALIDARG;
UINT cch = GetWindowTextLength(m_pgame->m_hwndDlg);
char *pszT = new char[cch+1];
if (!pszT)
return E_OUTOFMEMORY;
*pRet = SysAllocStringLen(NULL, cch);
if (!*pRet)
{
delete [] pszT;
return E_OUTOFMEMORY;
}
GetWindowText(m_pgame->m_hwndDlg, pszT, cch+1);
MultiByteToWideChar(CP_ACP, 0, pszT, -1, *pRet, cch+1);
delete [] pszT;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_Caption
(
BSTR bstr
)
{
WCHAR *pwsz = bstr ? bstr : L"";
MAKE_ANSIPTR_FROMWIDE(pszT, pwsz);
SetWindowText(m_pgame->m_hwndDlg, pszT);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_StatusText
(
BSTR* pRet
)
{
if (!pRet)
return E_INVALIDARG;
UINT cch = GetWindowTextLength(m_pgame->m_hwndStat);
char *pszT = new char[cch+1];
if (!pszT)
return E_OUTOFMEMORY;
*pRet = SysAllocStringLen(NULL, cch);
if (!*pRet)
{
delete [] pszT;
return E_OUTOFMEMORY;
}
GetWindowText(m_pgame->m_hwndStat, pszT, cch+1);
MultiByteToWideChar(CP_ACP, 0, pszT, -1, *pRet, cch+1);
delete [] pszT;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_StatusText
(
BSTR bstr
)
{
WCHAR *pwsz = bstr ? bstr : L"";
MAKE_ANSIPTR_FROMWIDE(pszT, pwsz);
m_pgame->m_pscore->SetStatusText(pszT);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Application
(
ISpruuidsApp** lppaReturn
)
{
return g_papp->QueryInterface(IID_ISpruuidsApp, (void **)lppaReturn);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Parent
(
ISpruuidsApp** lppaReturn
)
{
return g_papp->QueryInterface(IID_ISpruuidsApp, (void **)lppaReturn);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::StartGame
(
void
)
{
m_pgame->NewGame();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::EndGame
(
void
)
{
m_pgame->GameOver();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::RemoveAllSprites
(
void
)
{
m_pgame->m_pdisp->DestroyAll();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::NextLevel
(
void
)
{
m_pgame->NewLevel();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::Refresh
(
void
)
{
m_pgame->m_pdisp->Refresh();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::AddScore
(
int val
)
{
m_pgame->m_pscore->Add(val);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::StdBorderBounce
(
ISprite *psprite,
int brd
)
{
CSprite *pspr = SPRITEOFI(psprite);

if ((brd & SPR_brdTOP) && pspr->m_vyFull < 0)
{
pspr->m_vyFull = -pspr->m_vyFull;
pspr->IgnoreMove();
}
if ((brd & SPR_brdLEFT) && pspr->m_vxFull < 0)
{
pspr->m_vxFull = -pspr->m_vxFull;
pspr->IgnoreMove();
}
if ((brd & SPR_brdBOTTOM) && pspr->m_vyFull > 0)
{
pspr->m_vyFull = -pspr->m_vyFull;
pspr->IgnoreMove();
}
if ((brd & SPR_brdRIGHT) && pspr->m_vxFull > 0)
{
pspr->m_vxFull = -pspr->m_vxFull;
pspr->IgnoreMove();
}
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::StdBorderWrap
(
ISprite *psprite,
int brd
)
{
CSprite *pspr = SPRITEOFI(psprite);

if ((brd & SPR_brdTOP) && pspr->m_vyFull < 0)
pspr->m_y = pspr->m_pdisp->m_cy;
if ((brd & SPR_brdLEFT) && pspr->m_vxFull < 0)
pspr->m_x = pspr->m_pdisp->m_cx;
if ((brd & SPR_brdBOTTOM) && pspr->m_vyFull > 0)
pspr->m_y = -pspr->m_pimg->cy;
if ((brd & SPR_brdRIGHT) && pspr->m_vxFull > 0)
pspr->m_x = -pspr->m_pimg->cx;
return S_OK;
}


//---------------------------------------------------------------------------
// Generate a random number between 0 and n.
//---------------------------------------------------------------------------
int MyRand
(
int n
)
{
int t, u;
static nLast=0, tLast=0;

if (n <= 1)
return 0;

n &= RAND_MAX;
if (n == nLast)
t = tLast;
else
{
nLast = n;
for (t=2; t<n; t<<=1)
;
t--;
tLast = t;
}

do
{
u = t & rand();
} while (u >= n);
return u;
}


//---------------------------------------------------------------------------
// Init to random position which doesn't cause a collision event.
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::StdInitRand
(
ISprite *psprite,
VARIANT varUser
)
{
CSprite *pspr = SPRITEOFI(psprite);
CSprite *psprT;
LONG x, y, dx, dy;
int cx, cy;
int lUser = (varUser.vt == VT_I4) ? varUser.lVal : 0;
LONG dist = 8128;

cx = pspr->m_pimg->cx;
cy = pspr->m_pimg->cy;
do
{
Loop:
x = MyRand(pspr->m_pdisp->m_cx - cx);
y = MyRand(pspr->m_pdisp->m_cy - cy);
for (psprT=pspr->m_pdisp->m_psprFirst; psprT; psprT=psprT->m_psprNext)
{
if (!(psprT->m_psc->m_maskCollide & pspr->m_psc->m_maskCollide) && // if potential collision doesn't matter
x <= psprT->m_x+psprT->m_pimg->cx && x+cx >= psprT->m_x && // and we collide
y <= psprT->m_y+psprT->m_pimg->cy && y+cy >= psprT->m_y)
goto Loop; // then try another location
}
dx = (x - (pspr->m_pdisp->m_cx>>1));
dy = (y - (pspr->m_pdisp->m_cy>>1));
} while (dx*dx + dy*dy < dist);
pspr->m_x = (int)x;
pspr->m_y = (int)y;
return S_OK;
}


//---------------------------------------------------------------------------
// Init to random position along edge of disp.
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::StdInitEdge
(
ISprite *psprite,
VARIANT varUser
)
{
CSprite *pspr = SPRITEOFI(psprite);

if (rand() & 1)
{
pspr->m_x = MyRand(pspr->m_pdisp->m_cx - pspr->m_pimg->cx);
if (rand() & 1)
pspr->m_y = pspr->m_pdisp->m_cy - pspr->m_pimg->cy;
}
else
{
pspr->m_y = MyRand(pspr->m_pdisp->m_cy - pspr->m_pimg->cy);
if (rand() & 1)
pspr->m_x = pspr->m_pdisp->m_cx - pspr->m_pimg->cx;
}
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Paused
(
VARIANT_BOOL* pRet
)
{
*pRet = m_pgame->m_fPaused;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_Paused
(
VARIANT_BOOL val
)
{
m_pgame->Pause(!!val);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Width
(
int* pRet
)
{
*pRet = m_pgame->m_pdisp->m_cx;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_Width
(
int val
)
{
if (val < 20 || val > 1024)
return E_FAIL;
m_pgame->m_pscore->Size(val, m_pgame->m_pdisp->m_cy);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Height
(
int* pRet
)
{
*pRet = m_pgame->m_pdisp->m_cy;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_Height
(
int val
)
{
if (val < 20 || val > 1024)
return E_FAIL;
m_pgame->m_pscore->Size(m_pgame->m_pdisp->m_cx, val);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_BackColor
(
long* pRet
)
{
*pRet = m_pgame->m_pdisp->m_colorBack;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_BackColor
(
long val
)
{
if (val & 0xff000000)
return E_FAIL;
m_pgame->m_pdisp->SetBackColor(val);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Score
(
int* pRet
)
{
*pRet = m_pgame->m_pscore->GetScore();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_Score
(
int val
)
{
m_pgame->m_pscore->SetScore(val);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Level
(
int* pRet
)
{
*pRet = m_pgame->m_pscore->GetLevel();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_Level
(
int val
)
{
m_pgame->m_pscore->SetLevel(val);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_ShipCount
(
int* pRet
)
{
*pRet = m_pgame->m_pscore->GetCShip();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_ShipCount
(
int val
)
{
m_pgame->m_pscore->SetCShip(val);
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_ScoreFirst1Up
(
int* pRet
)
{
*pRet = m_pgame->m_pscore->m_scoreFirst1Up;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_ScoreFirst1Up
(
int val
)
{
if (val < 0)
return E_FAIL;
m_pgame->m_pscore->m_scoreFirst1Up = val;
if (m_pgame->m_pscore->m_scoreSecond1Up < val)
m_pgame->m_pscore->m_scoreSecond1Up = val;
if (m_pgame->m_pscore->GetScore() < m_pgame->m_pscore->m_scoreFirst1Up)
m_pgame->m_pscore->m_scoreNext1Up = val;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_ScoreSecond1Up
(
int* pRet
)
{
*pRet = m_pgame->m_pscore->m_scoreSecond1Up;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_ScoreSecond1Up
(
int val
)
{
if (val < 0)
return E_FAIL;
m_pgame->m_pscore->m_scoreSecond1Up = val;
if (val < m_pgame->m_pscore->m_scoreFirst1Up)
m_pgame->m_pscore->m_scoreFirst1Up = val;
if (m_pgame->m_pscore->GetScore() > m_pgame->m_pscore->m_scoreFirst1Up &&
m_pgame->m_pscore->GetScore() < m_pgame->m_pscore->m_scoreSecond1Up)
m_pgame->m_pscore->m_scoreNext1Up = val;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_DScoreNext1Up
(
int* pRet
)
{
*pRet = m_pgame->m_pscore->m_dscoreNext1Up;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_DScoreNext1Up
(
int val
)
{
if (val < 0)
return E_FAIL;
m_pgame->m_pscore->m_dscoreNext1Up = val;
if (m_pgame->m_pscore->GetScore() > m_pgame->m_pscore->m_scoreFirst1Up && m_pgame->m_pscore->GetScore() > 0)
{
m_pgame->m_pscore->m_scoreNext1Up = m_pgame->m_pscore->m_scoreFirst1Up;
while (m_pgame->m_pscore->m_scoreNext1Up < m_pgame->m_pscore->GetScore())
m_pgame->m_pscore->m_scoreNext1Up += m_pgame->m_pscore->m_dscoreNext1Up;
}
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_ShipsStart
(
int* pRet
)
{
*pRet = m_pgame->m_pscore->m_cshipStart;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_ShipsStart
(
int val
)
{
if (val < 0)
return E_FAIL;
m_pgame->m_pscore->m_cshipStart = val;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::get_Tag
(
VARIANT* pRet
)
{
if (!pRet)
return E_INVALIDARG;
VariantInit(pRet);
return VariantCopy(pRet, &m_pgame->m_varTag);
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::put_Tag
(
VARIANT val
)
{
return VariantCopy(&m_pgame->m_varTag, &val);
}



//***************************************************************************
// IDispatch Interface
//***************************************************************************

//---------------------------------------------------------------------------
// Method needed by COleAuto, so it can implement IDispatch for us.
//---------------------------------------------------------------------------
HRESULT CGameOA::GetTypeLibInfo
(
HINSTANCE *phinstOut,
const GUID **pplibidOut,
SHORT *pwMajLib,
SHORT *pwMinLib,
const CLSID **ppclsidOut,
const IID **ppiidOut,
ITypeLib ***ppptlOut
)
{
*phinstOut = g_hinst;
*pplibidOut = &LIBID_SPRUUIDS;
*pwMajLib = 1;
*pwMinLib = 0;
*ppclsidOut = &CLSID_Game;
*ppiidOut = &IID_IGame;
*ppptlOut = &g_ptlMain;
return S_OK;
}



//***************************************************************************
// IProvideClassInfo Interfaces
//***************************************************************************

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::GetClassInfo
(
ITypeInfo** pptinfoOut
)
{
HRESULT hr = ((COleAuto *)this)->CheckTypeInfo(0, 0x0409);
if (hr)
return hr;
*pptinfoOut = g_ptinfoClsGameOA;
(*pptinfoOut)->AddRef();
return S_OK;
}




//***************************************************************************
// IConnectionPointContainer Interface
//***************************************************************************

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::EnumConnectionPoints
(
LPENUMCONNECTIONPOINTS* ppEnum
)
{
return E_NOTIMPL; // UNDONE: Implement this method
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::FindConnectionPoint
(
REFIID iid,
LPCONNECTIONPOINT* ppCpOut
)
{
if (!ppCpOut)
return E_INVALIDARG;

if (iid == DIID_IGameEvents || iid == IID_IDispatch)
{
*ppCpOut = &m_cp;
(*ppCpOut)->AddRef();
return S_OK;
}

return E_NOINTERFACE;
}


//***************************************************************************
// Embedded IConnectionPoint Class
//***************************************************************************

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
CGameOA::XCP::XCP
(
void
)
{
m_cref = 1;
for (int i=0; i<GAME_cADVISE; i++)
m_rgpdisp[i] = NULL;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CGameOA::XCP::Close

( 
void
)
{
for (int i=0; i<SC_cADVISE; i++)
if (m_rgpdisp[i])
{
m_rgpdisp[i]->Release();
m_rgpdisp[i] = NULL;
}
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::XCP::QueryInterface
(
REFIID iid,
LPVOID* ppvObjOut
)
{
if (!ppvObjOut)
return E_INVALIDARG;

*ppvObjOut = NULL;

if (iid == IID_IUnknown)
*ppvObjOut = this->GetUnknown();
else if (iid == IID_IConnectionPoint)
*ppvObjOut = (IConnectionPoint *)this;

if (*ppvObjOut)
{
this->AddRef();
return S_OK;
}

return E_NOINTERFACE;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CGameOA::XCP::AddRef
(
void
)
{
return ++m_cref;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CGameOA::XCP::Release
(
void
)
{
CGame *pgame = this->PGAMEOA()->m_pgame;
ASSERT(m_cref, "bad m_cref");
m_cref--;
if (!m_cref && !pgame->m_cref)
{
delete pgame;
return 0;
}
return m_cref;
}


//***************************************************************************
// IConnectionPoint Interface
//***************************************************************************

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::XCP::GetConnectionInterface
(
IID* piid
)
{
if (!piid)
return E_INVALIDARG;

memcpy(piid, &DIID_ISpriteClassEvents, sizeof(IID));
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::XCP::GetConnectionPointContainer
(
IConnectionPointContainer** ppCPC
)
{
if (!ppCPC)
return E_INVALIDARG;

*ppCPC = this->PGAMEOA();
(*ppCPC)->AddRef();
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::XCP::Advise
(
IUnknown* punkSink,
DWORD* pdwCookie
)
{
IDispatch *psce = NULL;
IDispatch **ppdisp;
HRESULT hr;

if (!punkSink || !pdwCookie)
return E_INVALIDARG;
*pdwCookie = 0;

// Look for empty slot
for (ppdisp=m_rgpdisp; *ppdisp && ppdisp<&m_rgpdisp[GAME_cADVISE]; ppdisp++)
;
// Did we find one?
if (ppdisp >= &m_rgpdisp[GAME_cADVISE])
return E_FAIL; // UNDONE: Error?

// Now see if sink supports correct interface
hr = punkSink->QueryInterface(DIID_ISpriteClassEvents, (void **)&psce);
if (hr == E_NOINTERFACE)
{
hr = punkSink->QueryInterface(IID_IDispatch, (void **)&psce);
if (hr)
return hr;
}
ASSERT(psce, "QI but no ptr");

// Finish advise by stashing punkSink QI'd to our interface
*ppdisp = psce; // AddRef'd from QI
*pdwCookie = (ppdisp - m_rgpdisp) + 1;

return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::XCP::Unadvise
(
DWORD dwCookie
)
{
if (!dwCookie || dwCookie > GAME_cADVISE)
return E_INVALIDARG;

m_rgpdisp[dwCookie-1]->Release();
m_rgpdisp[dwCookie-1] = NULL;
return S_OK;
}


//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
STDMETHODIMP CGameOA::XCP::EnumConnections
(
LPENUMCONNECTIONS* ppEnum
)
{
return E_NOTIMPL; // UNDONE: Implement this method
}


//--- EOF -------------------------------------------------------------------