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.

577 lines
9.1 KiB

  1. /******************/
  2. /* SNAKE ROUTINES */
  3. /******************/
  4. #define _WINDOWS
  5. #include <windows.h>
  6. #include <port1632.h>
  7. #include "snake.h"
  8. #include "res.h"
  9. #include "rtns.h"
  10. #include "grafix.h"
  11. #include "blk.h"
  12. #include "pref.h"
  13. #include "sound.h"
  14. #include "util.h"
  15. /*** Global/Local Variables ***/
  16. BLK mpposblk[posMax]; /* The playing grid */
  17. POS posHead; /* current position of head */
  18. POS posTail; /* current position of tail */
  19. BOOL fHead; /* True if head is visible */
  20. BOOL fTail;
  21. BOOL fExit = fFalse;
  22. BOOL fPlum;
  23. POS posPlum;
  24. INT offPlumNS;
  25. INT offPlumEW;
  26. INT cDelayHead; /* Delay before head shows up */
  27. INT cDelayTail;
  28. INT cfoodRemain; /* Amount of food left to eat */
  29. INT cfoodUsed; /* Amount of food eaten */
  30. INT cLevel = 0; /* current level */
  31. INT cLives = cLivesStart; /* Count of Lives */
  32. #define idirMax 10
  33. DIR rgdir[idirMax];
  34. INT idirCurr;
  35. INT idirLast;
  36. INT ctickMove;
  37. INT ctickMoveMac = 4;
  38. INT ctickTime;
  39. INT ctickTimeMac = 1;
  40. #define cTimeLeftMax dxpTime
  41. INT cTimeLeft = cTimeLeftMax;
  42. #define lenStart 7
  43. extern INT score;
  44. extern BOOL fWipe;
  45. INT rgtickSkill[3] = {5, 3, 1};
  46. BLK mpdirdirblk[4][4] =
  47. {
  48. {blkBodyNS, blkBodySE, blkNull, blkBodySW}, /* N */
  49. {blkBodyNW, blkBodyEW, blkBodySW, blkNull }, /* E */
  50. {blkNull, blkBodyNE, blkBodyNS, blkBodyNW}, /* S */
  51. {blkBodyNE, blkNull, blkBodySE, blkBodyEW} /* W */
  52. };
  53. #define IncIDir(idir) (idir = (idir+1) % idirMax)
  54. #define BlkTailFromDir(dir) (blkTailN + (dir))
  55. #define BlkHeadFromDir(dir) (blkHeadN + (dir))
  56. #define DirFromBlk(blk) ((DIR) ((blk) & 0x0003))
  57. /*** Global/External Variables ***/
  58. extern STATUS status;
  59. extern PREF Preferences;
  60. extern BOOL fUpdateIni;
  61. extern INT cMoveScore;
  62. /****** C H A N G E P O S B L K ******/
  63. VOID ChangePosBlk(POS pos, BLK blk)
  64. {
  65. mpposblk[pos] = blk;
  66. DisplayPos(pos);
  67. }
  68. /****** D R O P F O O D ******/
  69. POS DropFood(VOID)
  70. {
  71. POS pos;
  72. while (mpposblk[pos = Rnd(posMax)] != blkNull)
  73. ;
  74. mpposblk[pos] = blkFood;
  75. return pos;
  76. }
  77. /****** P O S F R O M P O S D I R ******/
  78. POS PosFromPosDir(POS pos, DIR dir)
  79. {
  80. switch (dir)
  81. {
  82. case dirN:
  83. return (pos - xMax);
  84. case dirE:
  85. return (pos + 1);
  86. case dirS:
  87. return (pos + xMax);
  88. case dirW:
  89. return (pos - 1);
  90. #ifdef DEBUG
  91. default:
  92. Oops("PosFromPosDir: Invalid Direction");
  93. return pos;
  94. #endif
  95. }
  96. // program should not reach this section of code!
  97. return pos;
  98. }
  99. /****** D I R F R O M P O S P O S ******/
  100. DIR DirFromPosPos(POS posSrc, POS posDest)
  101. {
  102. INT dpos = posDest-posSrc;
  103. if (dpos == xMax)
  104. return dirS;
  105. else if (dpos == 1)
  106. return dirE;
  107. else if (dpos == -xMax)
  108. return dirN;
  109. #ifndef DEBUG
  110. else
  111. return dirW;
  112. #else
  113. else if (dpos == -1)
  114. return dirW;
  115. else
  116. Oops("DirFromPosPos: Invalid Direction");
  117. return dirN;
  118. #endif
  119. }
  120. /****** B L K T A I L F R O M B L K B L K ******/
  121. BLK BlkTailFromBlkBlk(BLK blkSrc, BLK blkDest)
  122. {
  123. if (blkDest == blkBodyNS || blkDest == blkBodyEW)
  124. return blkSrc;
  125. if (blkDest == blkBodyNE)
  126. if (blkSrc == blkTailW)
  127. return blkTailN;
  128. else
  129. return blkTailE;
  130. else if (blkDest == blkBodySE)
  131. if (blkSrc == blkTailW)
  132. return blkTailS;
  133. else
  134. return blkTailE;
  135. else if (blkDest == blkBodySW)
  136. if (blkSrc == blkTailE)
  137. return blkTailS;
  138. else
  139. return blkTailW;
  140. else /* if (blkDest == blkBodyNW) */
  141. if (blkSrc == blkTailE)
  142. return blkTailN;
  143. else
  144. return blkTailW;
  145. }
  146. /****** D O C H A N G E D I R ******/
  147. VOID DoChangeDir(DIR dir)
  148. {
  149. if (!fHead)
  150. return;
  151. if (((dir+2) % 4) == rgdir[idirLast]) /* Don't allow about faces */
  152. return;
  153. if (IncIDir(idirLast) == idirCurr) /* Watch for overflow */
  154. {
  155. if (--idirLast < 0)
  156. idirLast = idirMax-1;
  157. return;
  158. }
  159. rgdir[idirLast] = dir;
  160. }
  161. /****** D O C H A N G E R E L D I R ******/
  162. VOID DoChangeRelDir(DIR dirRel)
  163. {
  164. if ( (dirRel = rgdir[idirLast] + dirRel) < 0)
  165. dirRel = dirW;
  166. else if (dirRel > dirW)
  167. dirRel = dirN;
  168. DoChangeDir(dirRel);
  169. }
  170. /****** K I L L S N A K E ******/
  171. VOID KillSnake(VOID)
  172. {
  173. fHead = fTail = fFalse;
  174. fPlum = fFalse;
  175. if (cLives--)
  176. {
  177. PlayTune(TUNE_HITHEAD);
  178. StartLevel();
  179. }
  180. else
  181. {
  182. PlayTune(TUNE_LOSEGAME);
  183. cLives = 0;
  184. ClrStatusPlay();
  185. if (score > Preferences.HiScore)
  186. {
  187. /* Congrats, etc. */
  188. Preferences.HiScore = score;
  189. Preferences.HiLevel = cLevel;
  190. fUpdateIni = fTrue;
  191. }
  192. DisplayGameOver();
  193. }
  194. }
  195. /****** D E C T I M E ******/
  196. /* Decrement time left */
  197. VOID DecTime(VOID)
  198. {
  199. if (--cTimeLeft < 0)
  200. {
  201. INT i;
  202. for (i = 0; i < 3; i++)
  203. {
  204. DisplayPos(DropFood());
  205. cfoodRemain++;
  206. }
  207. cTimeLeft = cTimeLeftMax;
  208. DisplayTime();
  209. }
  210. else
  211. UpdateTime();
  212. }
  213. /****** D O M O V E ******/
  214. VOID DoMove(VOID)
  215. {
  216. POS posPrev;
  217. BLK blkPrev;
  218. DIR dir;
  219. if (fHead)
  220. {
  221. if (posHead == posLeave && fExit)
  222. {
  223. ChangePosBlk(posHead, blkBodyNS);
  224. fHead = fFalse;
  225. }
  226. else
  227. {
  228. /* Check heading/direction */
  229. if ((idirCurr != idirLast) && (posHead != posEnter))
  230. IncIDir(idirCurr);
  231. /* Change head into body */
  232. blkPrev = mpposblk[posPrev = posHead];
  233. posHead = PosFromPosDir(posPrev, dir = rgdir[idirCurr]);
  234. if (mpposblk[posHead] != blkNull)
  235. {
  236. if (mpposblk[posHead] < blkHeadN) /*** EAT FOOD ***/
  237. {
  238. AddScore(1);
  239. cTimeLeft = cTimeLeftMax;
  240. DisplayTime();
  241. if (--cfoodRemain == 0)
  242. {
  243. fExit = fTrue;
  244. ctickTime = tickNil;
  245. cTimeLeft = cTimeLeftMax;
  246. DisplayTime();
  247. ChangePosBlk(posLeave, blkNull);
  248. }
  249. fTail = fFalse;
  250. cDelayTail += 4;
  251. }
  252. else
  253. {
  254. KillSnake();
  255. return;
  256. }
  257. }
  258. ChangePosBlk(posPrev, mpdirdirblk[DirFromBlk(blkPrev)][dir]);
  259. ChangePosBlk(posHead, BlkHeadFromDir(dir));
  260. }
  261. }
  262. else if (cDelayHead)
  263. {
  264. if (--cDelayHead == 0)
  265. {
  266. ChangePosBlk(posHead, blkHeadN);
  267. fHead = fTrue;
  268. }
  269. }
  270. else
  271. {
  272. ctickMove = 1; /* Must be leaving (fExit == fTrue) */
  273. }
  274. if (fTail)
  275. {
  276. if (posTail == posLeave)
  277. {
  278. ChangePosBlk(posTail, blkNull);
  279. fTail = fFalse;
  280. if ((++cLevel % lvlMax) == 0)
  281. {
  282. if (ctickMoveMac > 1)
  283. ctickMoveMac--;
  284. PlayTune(TUNE_WINGAME);
  285. }
  286. else
  287. PlayTune(TUNE_WINLEVEL);
  288. StartLevel();
  289. AddScore(10);
  290. }
  291. else
  292. {
  293. /* Remove old tail */
  294. blkPrev = mpposblk[posPrev = posTail];
  295. if (posTail == posEnter)
  296. ChangePosBlk(posPrev, blkWallEW); /* Close entrance */
  297. else
  298. ChangePosBlk(posPrev, blkNull);
  299. /* Display new tail */
  300. posTail = PosFromPosDir(posPrev, DirFromBlk(blkPrev));
  301. ChangePosBlk(posTail, BlkTailFromBlkBlk(blkPrev, mpposblk[posTail]));
  302. }
  303. }
  304. else if (cDelayTail)
  305. {
  306. if (--cDelayTail == 0)
  307. {
  308. if (posTail == posEnter)
  309. {
  310. ChangePosBlk(posTail, blkTailN);
  311. }
  312. fTail = fTrue;
  313. }
  314. }
  315. }
  316. /****** F K I L L B O U N C E ******/
  317. BOOL FKillBounce(POS pos)
  318. {
  319. if (mpposblk[pos] != blkNull)
  320. {
  321. if (pos == posHead)
  322. KillSnake();
  323. return fTrue;
  324. }
  325. else
  326. if (pos == posLeave) /* Don't go into exit */
  327. return fTrue;
  328. else
  329. return fFalse;
  330. }
  331. /****** D O T I M E R ******/
  332. VOID DoTimer(VOID)
  333. {
  334. BOOL fBounce = 0; /* Variable - there must be a better way */
  335. if (cMoveScore != 0)
  336. MoveScore();
  337. if (!FPlay())
  338. return;
  339. if (--ctickMove == 0)
  340. {
  341. ctickMove = ctickMoveMac;
  342. DoMove();
  343. if (fPlum)
  344. {
  345. if (FKillBounce(posPlum + offPlumNS))
  346. {
  347. offPlumNS = -offPlumNS;
  348. fBounce = 1;
  349. }
  350. if (FKillBounce(posPlum + offPlumEW))
  351. {
  352. offPlumEW = -offPlumEW;
  353. fBounce = 2;
  354. }
  355. if (!fBounce)
  356. {
  357. if (FKillBounce(posPlum + offPlumNS + offPlumEW))
  358. {
  359. offPlumNS = -offPlumNS;
  360. offPlumEW = -offPlumEW;
  361. }
  362. }
  363. else if (FKillBounce(posPlum+offPlumNS + offPlumEW))
  364. {
  365. if (fBounce == 1)
  366. offPlumEW = -offPlumEW;
  367. else
  368. offPlumNS = -offPlumNS;
  369. }
  370. if (fPlum && (mpposblk[posPlum + offPlumNS + offPlumEW] == blkNull))
  371. {
  372. ChangePosBlk(posPlum, blkNull);
  373. posPlum += offPlumNS + offPlumEW;
  374. ChangePosBlk(posPlum, blkPlum);
  375. }
  376. }
  377. }
  378. else if (ctickMove < -50 && (cMoveScore==0)) /* This happens at the start of a game */
  379. {
  380. fPlum = (cLevel >= lvlMax);
  381. ctickMove = ctickMoveMac;
  382. ctickTime = ctickTimeMac;
  383. cTimeLeft = cTimeLeftMax;
  384. fWipe = fFalse;
  385. SetLevelColor();
  386. DisplayScreen();
  387. }
  388. if (--ctickTime == 0)
  389. {
  390. ctickTime = ctickTimeMac;
  391. DecTime();
  392. }
  393. }
  394. /****** S T A R T L E V E L *******/
  395. VOID StartLevel(VOID)
  396. {
  397. fPlum = fFalse;
  398. cTimeLeft = cTimeLeftMax;
  399. DisplayLevelNum();
  400. SetupLevelData();
  401. if (cLevel >= lvlMax)
  402. {
  403. offPlumNS = xMax;
  404. offPlumEW = 1;
  405. posPlum = 4*xMax + 3;
  406. while (mpposblk[posPlum] != blkNull)
  407. posPlum--;
  408. mpposblk[posPlum] = blkPlum;
  409. }
  410. /* Distribute Food */
  411. cfoodUsed = cfoodRemain = 10;
  412. while (cfoodUsed--)
  413. {
  414. DropFood();
  415. }
  416. /* Setup player position */
  417. fTail = fHead = fFalse;
  418. cDelayHead = 3;
  419. cDelayTail = lenStart;
  420. posTail = posHead = posEnter;
  421. ctickMove = -1; /* Indicate Starting Level */
  422. ctickTime = -1;
  423. rgdir[idirCurr=idirLast=0] = dirN;
  424. ClrStatusIcon();
  425. SetStatusPlay();
  426. }
  427. /****** S T A R T G A M E *******/
  428. VOID StartGame(INT lvl)
  429. {
  430. cLevel = lvl;
  431. cLives = cLivesStart;
  432. ctickMoveMac = max(0,rgtickSkill[Preferences.skill] - cLevel/lvlMax);
  433. ctickTimeMac = Preferences.skill ? 1 : 2;
  434. ResetScore();
  435. DisplayScore();
  436. StartLevel();
  437. }
  438.