Source code of Windows XP (NT5)
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.

679 lines
13 KiB

  1. /*************************************************
  2. * blockdoc.cpp *
  3. * *
  4. * Copyright (C) 1995-1999 Microsoft Inc. *
  5. * *
  6. *************************************************/
  7. // blockdoc.cpp : implementation of the CBlockDoc class
  8. //
  9. #include "stdafx.h"
  10. #include <imm.h>
  11. #include "cblocks.h"
  12. #include "dib.h"
  13. #include "dibpal.h"
  14. #include "spriteno.h"
  15. #include "sprite.h"
  16. #include "phsprite.h"
  17. #include "myblock.h"
  18. #include "splstno.h"
  19. #include "spritlst.h"
  20. #include "osbview.h"
  21. #include "blockvw.h"
  22. #include "slot.h"
  23. #include "mainfrm.h"
  24. #include "statis.h"
  25. #include "wave.h"
  26. #include "blockdoc.h"
  27. #ifdef _DEBUG
  28. #undef THIS_FILE
  29. static char BASED_CODE THIS_FILE[] = __FILE__;
  30. #endif
  31. CBitmap m_bmBlock;
  32. long GScore=0;
  33. extern CString GHint;
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CBlockDoc
  36. IMPLEMENT_DYNCREATE(CBlockDoc, CDocument)
  37. BEGIN_MESSAGE_MAP(CBlockDoc, CDocument)
  38. //{{AFX_MSG_MAP(CBlockDoc)
  39. ON_COMMAND(ID_OPTION_SIZE_12x10, OnOPTIONSIZE12x10)
  40. ON_COMMAND(ID_OPTION_SIZE_16x16, OnOPTIONSIZE16x16)
  41. ON_COMMAND(ID_OPTION_SIZE_4x4, OnOPTIONSIZE4x4)
  42. ON_COMMAND(ID_TEST_SOUND, OnTestSound)
  43. ON_COMMAND(ID_OPTION_BEGINER, OnOptionBeginer)
  44. ON_UPDATE_COMMAND_UI(ID_OPTION_BEGINER, OnUpdateOptionBeginer)
  45. ON_COMMAND(ID_OPTION_EXPERT, OnOptionExpert)
  46. ON_UPDATE_COMMAND_UI(ID_OPTION_EXPERT, OnUpdateOptionExpert)
  47. ON_UPDATE_COMMAND_UI(ID_OPTION_ORDINARY, OnUpdateOptionOrdinary)
  48. ON_COMMAND(ID_OPTION_ORDINARY, OnOptionOrdinary)
  49. ON_COMMAND(ID_OPTION_SOUND, OnOptionSound)
  50. ON_UPDATE_COMMAND_UI(ID_OPTION_SOUND, OnUpdateOptionSound)
  51. ON_COMMAND(ID_FILE_STATISTIC, OnFileStatistic)
  52. ON_COMMAND(IDM_TEST, OnTest)
  53. //}}AFX_MSG_MAP
  54. END_MESSAGE_MAP()
  55. /////////////////////////////////////////////////////////////////////////////
  56. // CBlockDoc construction/destruction
  57. CBlockDoc::CBlockDoc()
  58. {
  59. m_pBkgndDIB = NULL;
  60. m_nRow = 10;
  61. m_nCol = 12;
  62. m_nRowHeight = 32;
  63. m_nColWidth = 32;
  64. m_pSlotManager = NULL;
  65. m_bSound = TRUE;
  66. m_nExpertise = LEVEL_BEGINNER;
  67. m_pdibArrow = NULL;
  68. m_bmBlock.LoadBitmap(IDB_BLOCK);
  69. }
  70. CBlockDoc::~CBlockDoc()
  71. {
  72. if (m_pBkgndDIB) {
  73. delete m_pBkgndDIB;
  74. }
  75. m_SpriteList.RemoveAll();
  76. if (m_pSlotManager)
  77. delete m_pSlotManager;
  78. }
  79. char* CBlockDoc::GetChar()
  80. {
  81. int Hi;
  82. int Lo;
  83. static char szBuf[4];
  84. switch (m_nExpertise)
  85. {
  86. case LEVEL_EXPERT:
  87. {
  88. BOOL bAgain = FALSE;
  89. int nSafeCount = 0;
  90. do
  91. {
  92. Hi = 0xA4 + MyRand() % (0xF9-0xA4);
  93. if ((Hi >= 0xC6) && (Hi <= 0xC8))
  94. {
  95. nSafeCount++;
  96. if (nSafeCount > 5)
  97. {
  98. Hi = 0xA4;
  99. bAgain = FALSE;
  100. }
  101. else
  102. bAgain = TRUE;
  103. }
  104. } while (bAgain);
  105. }
  106. break;
  107. case LEVEL_ORDINARY:
  108. Hi = 0xA4 + MyRand() % (0xC6 - 0xA4);
  109. break;
  110. case LEVEL_BEGINNER:
  111. Hi = 0xA4 + MyRand() % 4;
  112. break;
  113. }
  114. Lo = (MyRand() % 2) ? 0x40 + MyRand() % 0x3F :
  115. 0xA1 + MyRand() % 0x5E ;
  116. szBuf[0] = (BYTE) Hi;
  117. szBuf[1] = (BYTE) Lo;
  118. szBuf[2] = 0;
  119. return szBuf;
  120. }
  121. // helper to load a ball sprite
  122. CBlock* CBlockDoc::LoadBlock(UINT idRes, int iMass, int iX, int iY, int iVX, int iVY)
  123. {
  124. static int nc=0;
  125. char* pszBuf=NULL;
  126. CDC dcMem;
  127. dcMem.CreateCompatibleDC(NULL);
  128. CBitmap* pOldBmp = dcMem.SelectObject(&m_bmBlock);
  129. pszBuf = GetChar();
  130. CSize szChar = dcMem.GetTextExtent(pszBuf,lstrlen(pszBuf));
  131. dcMem.SetBkColor(RGB(192,192,192));
  132. dcMem.SetTextColor(RGB(0,0,255));
  133. dcMem.TextOut((GetColWidth()-szChar.cx)/2,(GetRowHeight()-szChar.cy)/2,pszBuf,lstrlen(pszBuf));
  134. dcMem.SelectObject(pOldBmp);
  135. dcMem.DeleteDC();
  136. CBlock* pBlock = new CBlock;
  137. if (!pBlock->Load(&m_bmBlock)) {
  138. char buf[64];
  139. sprintf(buf, "Failed to load bitmap\n");
  140. AfxMessageBox(buf);
  141. delete pBlock;
  142. return NULL;
  143. }
  144. pBlock->SetMass(iMass);
  145. pBlock->SetPosition(iX, iY);
  146. pBlock->SetVelocity(iVX, iVY);
  147. pBlock->SetCode(MAKEWORD(BYTE(pszBuf[1]),BYTE(pszBuf[0])));
  148. return pBlock;
  149. UNREFERENCED_PARAMETER(idRes);
  150. }
  151. BOOL m_bsndFire;
  152. BOOL m_bsndGround;
  153. BOOL m_bsndHit;
  154. CWave m_sndHit;
  155. CWave m_sndGround;
  156. CWave m_sndFire;
  157. BOOL CBlockDoc::OnNewDocument()
  158. {
  159. if (!CDocument::OnNewDocument())
  160. return FALSE;
  161. m_nSeed = (int)(GetTickCount() % 65536);
  162. CBlockView* pView = GetBlockView();
  163. ASSERT(pView);
  164. m_SpriteList.m_NotifyObj.SetView(pView);
  165. // load the background image
  166. CDIB* pDIB = new CDIB;
  167. pDIB->Create(m_nColWidth * m_nCol,m_nRowHeight * m_nRow);
  168. SetBackground(pDIB);
  169. if (sndPlaySound("",SND_SYNC))
  170. {
  171. m_bsndFire = m_sndFire.LoadResource(IDR_SNDFIRE);
  172. m_bsndHit = m_sndHit.LoadResource(IDR_SNDHIT);
  173. m_bsndGround = m_sndGround.LoadResource(IDR_SNDGROUND);
  174. }
  175. else
  176. {
  177. m_bsndFire = FALSE;
  178. m_bsndHit = FALSE;
  179. m_bsndGround = FALSE;
  180. }
  181. if (m_pSlotManager)
  182. delete m_pSlotManager;
  183. m_pSlotManager = new CSlotManager(this);
  184. if (m_pdibArrow)
  185. delete m_pdibArrow;
  186. CBitmap bmArrow;
  187. bmArrow.LoadBitmap(IDB_ARROW);
  188. m_pdibArrow = new CBlock;
  189. m_pdibArrow->Load(&bmArrow);
  190. GScore = 0;
  191. SetModifiedFlag(FALSE);
  192. m_nTotalWords =0;
  193. m_nTotalHitWords =0;
  194. m_nMissedHit =0;
  195. m_nHitInMoving =0;
  196. m_nHitInStill =0;
  197. return TRUE;
  198. }
  199. void CBlockDoc::DeleteContents()
  200. {
  201. if (m_pSlotManager)
  202. {
  203. delete m_pSlotManager;
  204. m_pSlotManager = NULL;
  205. }
  206. if (m_pdibArrow)
  207. {
  208. delete m_pdibArrow;
  209. m_pdibArrow = NULL;
  210. }
  211. //sndPlaySound(NULL,SND_ASYNC);
  212. CDocument::DeleteContents();
  213. }
  214. /////////////////////////////////////////////////////////////////////////////
  215. // CBlockDoc serialization
  216. void CBlockDoc::Serialize(CArchive& ar)
  217. {
  218. CDocument::Serialize(ar);
  219. if (ar.IsStoring()) {
  220. if (m_pBkgndDIB) {
  221. ar << (DWORD) 1; // say we have a bkgnd
  222. m_pBkgndDIB->Serialize(ar);
  223. } else {
  224. ar << (DWORD) 0; // say we have no bkgnd
  225. }
  226. m_SpriteList.Serialize(ar);
  227. } else {
  228. DWORD dw;
  229. // see if we have a background to load
  230. ar >> dw;
  231. if (dw != 0) {
  232. CDIB *pDIB = new CDIB;
  233. pDIB->Serialize(ar);
  234. // Attach it to the document
  235. SetBackground(pDIB);
  236. }
  237. // read the sprite list
  238. m_SpriteList.Serialize(ar);
  239. SetModifiedFlag(FALSE);
  240. UpdateAllViews(NULL, 0, NULL);
  241. }
  242. }
  243. /////////////////////////////////////////////////////////////////////////////
  244. // CBlockDoc diagnostics
  245. #ifdef _DEBUG
  246. void CBlockDoc::AssertValid() const
  247. {
  248. CDocument::AssertValid();
  249. }
  250. void CBlockDoc::Dump(CDumpContext& dc) const
  251. {
  252. CDocument::Dump(dc);
  253. }
  254. #endif //_DEBUG
  255. /////////////////////////////////////////////////////////////////////////////
  256. // helper functions
  257. // return a pointer to the off-screen buffered view
  258. CBlockView* CBlockDoc::GetBlockView()
  259. {
  260. POSITION pos;
  261. pos = GetFirstViewPosition();
  262. ASSERT(pos);
  263. CBlockView *pView = (CBlockView *)GetNextView(pos);
  264. ASSERT(pView);
  265. ASSERT(pView->IsKindOf(RUNTIME_CLASS(CBlockView)));
  266. return pView;
  267. }
  268. /////////////////////////////////////////////////////////////////////////////
  269. // CBlockDoc commands
  270. // Set a new background DIB
  271. BOOL CBlockDoc::SetBackground(CDIB* pDIB)
  272. {
  273. // Delete any existing sprites
  274. m_SpriteList.RemoveAll();
  275. // Delete any existing background DIB and set the new one
  276. if (m_pBkgndDIB) delete m_pBkgndDIB;
  277. m_pBkgndDIB = pDIB;
  278. // Tell the view that it needs to create a new buffer
  279. // and palette
  280. CBlockView* pView = GetBlockView();
  281. ASSERT(pView);
  282. return pView->NewBackground(m_pBkgndDIB);
  283. }
  284. void CBlockDoc::GetSceneRect(CRect* prc)
  285. {
  286. if (!m_pBkgndDIB) return;
  287. m_pBkgndDIB->GetRect(prc);
  288. }
  289. void CBlockDoc::Land()
  290. {
  291. m_pSlotManager->Land();
  292. }
  293. void CBlockDoc::Tick()
  294. {
  295. int nSlotNo;
  296. static BOOL bInLoop = FALSE;
  297. if (! bInLoop)
  298. {
  299. bInLoop = TRUE;
  300. if ((nSlotNo = m_pSlotManager->GetIdleSlot()) >= 0)
  301. GenerateBlock(nSlotNo);
  302. bInLoop = FALSE;
  303. }
  304. else
  305. {
  306. MessageBeep(0);
  307. TRACE("****************** Problem \n");
  308. }
  309. }
  310. void CBlockDoc::GenerateBlock(int nSlotNo)
  311. {
  312. int vY=0;
  313. switch(m_nExpertise)
  314. {
  315. case LEVEL_EXPERT:
  316. vY = 500 + MyRand() % 1000;
  317. break;
  318. case LEVEL_ORDINARY:
  319. vY = 300 + MyRand() % 500;
  320. break;
  321. case LEVEL_BEGINNER:
  322. vY = 100 + MyRand() % 200;
  323. break;
  324. default:
  325. vY = 100 + MyRand() % 1000;
  326. }
  327. CBlock* pBlock = LoadBlock(IDB_BLOCK,MyRand() % 600+100,m_nColWidth*nSlotNo,-m_nRowHeight,0,vY);
  328. m_SpriteList.Insert(pBlock);
  329. m_pSlotManager->AddRunningBlock(nSlotNo,pBlock);
  330. GetBlockView()->NewSprite(pBlock);
  331. m_nTotalWords++;
  332. }
  333. void CBlockDoc::GameOver(BOOL bHighScore)
  334. {
  335. GetBlockView()->GameOver(bHighScore);
  336. SoundOver();
  337. POSITION pPos = m_SpriteList.GetHeadPosition();
  338. for ( ; pPos; )
  339. {
  340. CBlock *pBlock = (CBlock *) m_SpriteList.GetNext(pPos);
  341. pBlock->Inverse();
  342. }
  343. UpdateAllViews(NULL);
  344. }
  345. void CBlockDoc::Promote()
  346. {
  347. switch (GSpeed)
  348. {
  349. case SPEED_FAST:
  350. //GetBlockView()->SendMessage(WM_COMMAND,ID_ACTION_SLOW);
  351. break;
  352. case SPEED_NORMALFAST:
  353. GetBlockView()->SendMessage(WM_COMMAND,ID_ACTION_FAST);
  354. break;
  355. case SPEED_NORMAL:
  356. GetBlockView()->SendMessage(WM_COMMAND,ID_ACTION_NORMALFAST);
  357. break;
  358. case SPEED_NORMALSLOW:
  359. GetBlockView()->SendMessage(WM_COMMAND,ID_ACTION_NORMAL);
  360. break;
  361. case SPEED_SLOW:
  362. GetBlockView()->SendMessage(WM_COMMAND,ID_ACTION_NORMALSLOW);
  363. break;
  364. }
  365. }
  366. void CBlockDoc::Hit(WORD wCode)
  367. {
  368. int nLayer=0;
  369. CBlock *pBlock=m_pSlotManager->Hit(wCode,nLayer);
  370. if (pBlock)
  371. {
  372. SoundHit();
  373. m_pdibArrow->Coverage(pBlock);
  374. if (nLayer > 1)
  375. {
  376. m_nHitInMoving++;
  377. GScore += nLayer;
  378. }
  379. else
  380. {
  381. GScore++;
  382. m_nHitInStill++;
  383. }
  384. m_nTotalHitWords++;
  385. }
  386. else
  387. {
  388. SoundFire();
  389. m_nMissedHit++;
  390. }
  391. if ((m_nTotalHitWords+1) % 20 == 0)
  392. {
  393. Promote();
  394. }
  395. if (GScore > 9999999999L)
  396. {
  397. GameOver(TRUE);
  398. }
  399. }
  400. void CBlockDoc::OnOPTIONSIZE12x10()
  401. {
  402. m_nRow = 10;
  403. m_nCol = 12;
  404. AfxGetApp()->m_pMainWnd->SendMessage(WM_COMMAND,ID_FILE_NEW);
  405. }
  406. void CBlockDoc::OnOPTIONSIZE16x16()
  407. {
  408. m_nRow = 16;
  409. m_nCol = 16;
  410. AfxGetApp()->m_pMainWnd->SendMessage(WM_COMMAND,ID_FILE_NEW);
  411. }
  412. void CBlockDoc::OnOPTIONSIZE4x4()
  413. {
  414. m_nRow = 4;
  415. m_nCol = 4;
  416. AfxGetApp()->m_pMainWnd->SendMessage(WM_COMMAND,ID_FILE_NEW);
  417. }
  418. void CBlockDoc::SoundFire()
  419. {
  420. if (!m_bSound)
  421. return;
  422. if (m_bsndFire)
  423. m_sndFire.Play();
  424. else
  425. {
  426. int tone =1000;
  427. int time = 1;
  428. for ( ; tone>100; )
  429. {
  430. Beep(tone,time);
  431. tone -= 50;
  432. }
  433. }
  434. }
  435. void CBlockDoc::SoundHit()
  436. {
  437. if (!m_bSound)
  438. return;
  439. if (m_bsndHit)
  440. m_sndHit.Play();
  441. else
  442. {
  443. int tone =900;
  444. int time = 2;
  445. for ( ; tone<=1200; )
  446. {
  447. Beep(tone,time);
  448. tone += 50;
  449. }
  450. }
  451. }
  452. void CBlockDoc::SoundAppear()
  453. {
  454. if (!m_bSound)
  455. return;
  456. int tone =200;
  457. int time = 1;
  458. for ( ; time<5; )
  459. {
  460. Beep(tone,time);
  461. (time %2) ? tone +=100 : tone -=50;
  462. time++;
  463. }
  464. }
  465. void CBlockDoc::SoundGround()
  466. {
  467. if (!m_bSound)
  468. return;
  469. if (m_bsndGround)
  470. m_sndGround.Play();
  471. else
  472. {
  473. int tone =1000;
  474. int time = 1;
  475. for ( ; time<5; )
  476. {
  477. Beep(tone,time);
  478. tone +=100;
  479. time++;
  480. }
  481. }
  482. }
  483. void CBlockDoc::SoundOver()
  484. {
  485. if (!m_bSound)
  486. return;
  487. MessageBeep(MB_ICONASTERISK );
  488. int tone[8] = {200,200,252,252,300,300,225,225};
  489. int time=30;
  490. for (int j=0; j<5; j++)
  491. for (int i=1; i<8; i++)
  492. Beep(tone[i],time);
  493. }
  494. void CBlockDoc::OnTestSound()
  495. {
  496. SoundHit();
  497. }
  498. void CBlockDoc::OnOptionBeginer()
  499. {
  500. m_nExpertise = LEVEL_BEGINNER;
  501. AfxGetApp()->OnIdle(RANK_USER);
  502. }
  503. void CBlockDoc::OnUpdateOptionBeginer(CCmdUI* pCmdUI)
  504. {
  505. pCmdUI->SetCheck(m_nExpertise == LEVEL_BEGINNER ? 1 : 0);
  506. }
  507. void CBlockDoc::OnOptionExpert()
  508. {
  509. m_nExpertise = LEVEL_EXPERT;
  510. AfxGetApp()->OnIdle(RANK_USER);
  511. }
  512. void CBlockDoc::OnUpdateOptionExpert(CCmdUI* pCmdUI)
  513. {
  514. pCmdUI->SetCheck(m_nExpertise == LEVEL_EXPERT ? 1 : 0);
  515. }
  516. void CBlockDoc::OnOptionOrdinary()
  517. {
  518. m_nExpertise = LEVEL_ORDINARY;
  519. AfxGetApp()->OnIdle(RANK_USER);
  520. }
  521. void CBlockDoc::OnUpdateOptionOrdinary(CCmdUI* pCmdUI)
  522. {
  523. pCmdUI->SetCheck(m_nExpertise == LEVEL_ORDINARY ? 1 : 0);
  524. }
  525. void CBlockDoc::OnOptionSound()
  526. {
  527. m_bSound = ! m_bSound;
  528. }
  529. void CBlockDoc::OnUpdateOptionSound(CCmdUI* pCmdUI)
  530. {
  531. pCmdUI->SetCheck(m_bSound ? 1 : 0);
  532. }
  533. void CBlockDoc::OnFileStatistic()
  534. {
  535. CStatisticDlg sta(this);
  536. GetBlockView()->SetSpeed(0);
  537. sta.DoModal();
  538. GetBlockView()->SetSpeed(GSpeed);
  539. }
  540. void CBlockDoc::Remove(CBlock* pBlock)
  541. {
  542. m_SpriteList.Remove(pBlock);
  543. delete pBlock;
  544. }
  545. WORD CBlockDoc::GetFocusChar(CPoint pt)
  546. {
  547. POSITION pPos = m_SpriteList.GetHeadPosition();
  548. for (;pPos; )
  549. {
  550. CBlock* pBlock = (CBlock*) m_SpriteList.GetNext(pPos);
  551. CRect rc = CRect(pBlock->GetX(),pBlock->GetY(),pBlock->GetX()+m_nColWidth,pBlock->GetY()+m_nRowHeight);
  552. if (rc.PtInRect(pt))
  553. return (pBlock->GetCode());
  554. }
  555. return 0;
  556. }
  557. #define MAX_COMP 10
  558. #define MAX_KEY 5
  559. BOOL CBlockDoc::GetKeyStroke(WORD wCode)
  560. {
  561. HKL hkl = GetKeyboardLayout(0);
  562. if ( hkl == 0 || !ImmIsIME(hkl) )
  563. return FALSE;
  564. HIMC himc = ImmGetContext(GetBlockView()->GetSafeHwnd());
  565. char buf[sizeof(CANDIDATELIST)+(sizeof(DWORD) + sizeof(WORD) * MAX_KEY + sizeof(TCHAR) ) * MAX_COMP];
  566. char lpsrc[3];
  567. lpsrc[0] = HIBYTE(wCode);
  568. lpsrc[1] = LOBYTE(wCode);
  569. lpsrc[2] = 0;
  570. UINT rc = ImmGetConversionList( hkl, himc,
  571. lpsrc, (CANDIDATELIST *)buf,
  572. (UINT)sizeof(buf),
  573. GCL_REVERSECONVERSION );
  574. ImmReleaseContext(GetBlockView()->GetSafeHwnd(),himc);
  575. if (rc == 0)
  576. return FALSE;
  577. if (((CANDIDATELIST *) buf)->dwCount == 0)
  578. return FALSE;
  579. GHint = CString(buf+ ((CANDIDATELIST *) buf)->dwOffset[0]);
  580. return TRUE;
  581. }
  582. void CBlockDoc::OnTest()
  583. {
  584. }