samegame.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. {
  2. $Id$
  3. This program is both available in XTDFPC as in the FPC demoes.
  4. Copyright (C) 1999 by Marco van de Voort
  5. SameGame is a standard game in GNOME and KDE. I liked it, and I
  6. automatically brainstormed how I would implement it.
  7. It turned out to be really easy, and is basically only 100 lines or so.
  8. The game demonstrates some features of the MSMOUSE unit, and some of
  9. the Crt unit.
  10. See the file COPYING.FPC, included in this distribution,
  11. for details about the copyright.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. **********************************************************************}
  16. PROGRAM SameGame;
  17. Uses Crt,GameUnit;
  18. CONST FieldX = 10; {Top left playfield coordinates}
  19. FieldY = 3; {Top left playfield coordinates}
  20. PlayFieldXDimension = 20; {Dimensions of playfield}
  21. PlayFieldYDimension = 15;
  22. {Used colors. Colors[0..2] are the colors used on the playfield, Colors[3]
  23. is the background and Colors[4] is the color used to mark the pieces}
  24. Colors : ARRAY [0..4] OF LONGINT = (White,Blue,Red,Black,LightMagenta);
  25. TYPE PlayFieldType=ARRAY[0..PlayFieldXDimension-1,0..PlayFieldYDimension-1] OF BYTE;
  26. PROCEDURE DisplayPlayField(CONST PlayField:PlayFieldType);
  27. {Screen routine, simply puts the array Playfield on screen.
  28. Both used for displaying the normal grid as the grid with a certain area marked}
  29. VAR X,Y : LONGINT;
  30. BEGIN
  31. FOR Y:=0 TO PlayFieldYDimension-1 DO
  32. BEGIN
  33. GotoXY(FieldX,Y+FieldY);
  34. FOR X:=0 TO PlayFieldXDimension-1 DO
  35. BEGIN
  36. TextColor(Colors[PlayField[X,Y]]);
  37. Write(#219#219);
  38. END;
  39. END;
  40. END;
  41. PROCEDURE ShowHelp;
  42. {Shows some explanation of the game and waits for a key}
  43. VAR I : LONGINT;
  44. BEGIN
  45. FOR I:=2 TO 24 DO
  46. BEGIN
  47. GotoXY(1,I);
  48. ClrEol;
  49. END;
  50. GotoXY(1,3); TextColor(White);
  51. Write('SAMEGAME');
  52. SetDefaultColor;
  53. WriteLn(' is a small game, with a principle copied from some KDE game');
  54. WriteLn;
  55. WriteLn('I tried to implement it under Go32V2 to demonstrate the MsMouse unit');
  56. Writeln('When it worked, I tried to get it running under Linux. I succeeded,');
  57. Writeln('but the mouse unit of the API doesn'#39't work with GPM 1.17');
  58. Writeln;
  59. WriteLn('If you move over the playfield, aggregates of one color will be marked');
  60. Writeln('in purple. If you then press the left mouse button, that aggregate will');
  61. Writeln('disappear, and the playfield will collapse to the bottom-left. Please');
  62. Writeln('keep in mind that only an aggregate of two blocks or more will disappear.');
  63. Writeln;
  64. Writeln('For every aggregate you let disappear you get points, but the score is');
  65. Writeln('quadratic proportional to the number of blocks killed. So 4 times killing');
  66. Writeln(' a 4 block aggregate scores 4 points, and one time 16 blocks will score 64');
  67. Writeln('blocks. The purpose of the game is obtaining the highscore');
  68. Writeln;
  69. Writeln('If you manage to kill the entire playfield, you'#39'll get a bonus');
  70. Writeln;
  71. WriteLn('Press any key to get back to the game');
  72. GetKey;
  73. END;
  74. VAR MarkField,PlayField : PlayFieldType; {The playfield, and the marked form}
  75. CubesMarked : LONGINT; {Cubes currently marked}
  76. Score : LONGINT; {The current score}
  77. LastScore : LONGINT;
  78. PROCEDURE ShowButtons;
  79. {Shows the clickable buttons}
  80. BEGIN
  81. TextColor(Yellow); TextBackGround(Blue);
  82. GotoXY(60,5); Write('NEW game');
  83. GotoXY(60,6); Write('HELP');
  84. GotoXY(60,7); Write('END game');
  85. {$IFDEF Linux}
  86. GotoXY(60,8); Write('Force IBM charset');
  87. {$ENDIF}
  88. SetDefaultColor;
  89. END;
  90. FUNCTION PlayFieldPiecesLeft:LONGINT;
  91. {Counts pieces/cubes/blocks left on the playfield}
  92. VAR I,J,K : LONGINT;
  93. BEGIN
  94. K:=0;
  95. FOR I:=0 TO PlayFieldXDimension-1 DO
  96. FOR J:=0 TO PlayFieldYDimension-1 DO
  97. IF PlayField[I,J]<>3 THEN
  98. INC(K);
  99. PlayFieldPiecesLeft:=K;
  100. END;
  101. PROCEDURE ShowScore;
  102. {Simply procedure to update the score}
  103. BEGIN
  104. TextColor(White);
  105. GotoXY(20,23); Write(' ':20);
  106. GotoXY(20,23); Write('Score : ',Score);
  107. SetDefaultColor;
  108. END;
  109. FUNCTION CubesToScore : LONGINT;
  110. {Function to calculate score from the number of cubes. Should have a higher
  111. order than linear, or the purpose of the game disappears}
  112. BEGIN
  113. CubesToScore:=(CubesMarked*CubesMarked) DIV 4;
  114. END;
  115. PROCEDURE MarkAfield(X,Y:LONGINT);
  116. {Recursively marks the area adjacent to (X,Y);}
  117. VAR TargetColor : LONGINT;
  118. PROCEDURE MarkRecur(X1,Y1:LONGINT);
  119. {Marks X1,Y1, checks if neighbours (horizontally or vertically) are the
  120. same color}
  121. BEGIN
  122. IF (PlayField[X1,Y1]=TargetColor) AND (MarkField[X1,Y1]<>4) THEN
  123. BEGIN
  124. MarkField[X1,Y1]:=4;
  125. INC(CubesMarked);
  126. IF X1>0 THEN
  127. MarkRecur(X1-1,Y1);
  128. IF Y1>0 THEN
  129. MarkRecur(X1,Y1-1);
  130. IF X1<(PlayFieldXDimension-1) THEN
  131. MarkRecur(X1+1,Y1);
  132. IF Y1<(PlayFieldYDimension-1) THEN
  133. MarkRecur(X1,Y1+1);
  134. END;
  135. END;
  136. BEGIN
  137. CubesMarked:=0;
  138. TargetColor:=PlayField[X,Y];
  139. IF TargetColor<>3 THEN {Can't mark black space}
  140. MarkRecur(X,Y);
  141. END;
  142. PROCEDURE FillPlayfield;
  143. {Initial version, probably not nice to play with.
  144. Some Life'ish algoritm would be better I think. (so that more aggregates exist)}
  145. VAR X,Y,Last,Now : LONGINT;
  146. BEGIN
  147. Last:=0;
  148. FOR X:=0 TO PlayFieldXDimension-1 DO
  149. FOR Y:=0 TO PlayFieldYDimension-1 DO
  150. BEGIN
  151. Now:=RANDOM(4);
  152. IF Now=3 THEN
  153. Now:=Last;
  154. PlayField[X,Y]:=Now;
  155. Last:=Now;
  156. END;
  157. MarkField:=PlayField;
  158. END;
  159. PROCEDURE Colapse;
  160. {Processes the playfield if the mouse button is used.
  161. First the procedure deletes the marked area, and let gravity do its work
  162. Second the procedure uses as if some gravity existed on the left of the
  163. playfield }
  164. VAR X, Y,J :LONGINT;
  165. BEGIN
  166. {Vertical colapse: All marked pieces are deleted, and let gravity do it's work}
  167. IF CubesMarked>1 THEN
  168. BEGIN
  169. FOR X:=0 TO PlayFieldXDimension-1 DO
  170. BEGIN
  171. Y:=PlayFieldYDimension-1; J:=Y;
  172. REPEAT
  173. IF MarkField[X,Y]<>4 THEN
  174. BEGIN
  175. PlayField[X,J]:=PlayField[X,Y];
  176. DEC(J);
  177. END;
  178. DEC(Y);
  179. UNTIL Y<0;
  180. FOR Y:=0 TO J DO
  181. PlayField[X,Y]:=3;
  182. END;
  183. J:=0;
  184. FOR X:=PlayFieldXDimension-2 DOWNTO 0 DO
  185. BEGIN
  186. IF PlayfIeld[X,PlayFieldYDimension-1]=3 THEN
  187. BEGIN
  188. Move(PlayfIeld[X+1,0],PlayField[X,0],PlayFieldYDimension*(PlayFieldXDimension-X-1));
  189. INC(J);
  190. END;
  191. END;
  192. IF J<>0 THEN
  193. FillChar(PlayField[PlayFieldXDimension-J,0],J*PlayFieldYDimension,#3);
  194. INC(Score,CubesToScore);
  195. ShowScore;
  196. END;
  197. END;
  198. PROCEDURE BuildScreen;
  199. {Some procedures that build the screen}
  200. BEGIN
  201. ClrScr; Score:=0;
  202. ShowScore;
  203. ShowButtons;
  204. ShowHighScore;
  205. ShowMouse;
  206. GotoXY(1,1);
  207. TextColor(Yellow);
  208. Write('SameGame v0.02');
  209. TextColor(White);
  210. Write(' A demo for the ');
  211. TextColor(Yellow); Write('FPC');
  212. TextColor(White); Write(' API or MsMouse unit. By Marco van de Voort');
  213. SetDefaultColor;
  214. IF LastScore<>0 THEN
  215. BEGIN
  216. GotoXY(10,20);
  217. Write('The score in the last game was :',LastScore);
  218. END;
  219. DisplayPlayField(PlayField);
  220. MarkField:=PlayField;
  221. END;
  222. PROCEDURE DoMainLoopMouse;
  223. {The main game loop. The entire game runs in this procedure, the rest is
  224. initialisation/finalisation (like loading and saving highscores etc etc)}
  225. VAR X,Y,
  226. MX,MY,MState,Dummy : LONGINT;
  227. EndOfGame : LONGINT;
  228. S : String;
  229. BEGIN
  230. RANDOMIZE;
  231. REPEAT
  232. FillPlayField;
  233. BuildScreen;
  234. EndOfGame:=0;
  235. REPEAT
  236. GetMouseState(MX,MY,MState);
  237. X:=MX SHR 3;
  238. Y:=MY SHR 3;
  239. IF PlayFieldPiecesLeft=0 THEN
  240. BEGIN
  241. INC(Score,1000);
  242. EndOfGame:=1;
  243. END
  244. ELSE
  245. BEGIN
  246. IF (X>=60) AND (X<=69) THEN
  247. BEGIN
  248. IF (MState AND LButton) <>0 THEN {If leftbutton pressed,}
  249. BEGIN
  250. IF Y=4 THEN
  251. EndOfGame:=1;
  252. IF Y=6 THEN
  253. EndOfGame:=2;
  254. IF (EndOfGame>0) AND (PlayFieldPiecesLeft=0) THEN
  255. INC(Score,1000);
  256. IF Y=5 THEN
  257. BEGIN
  258. ShowHelp;
  259. BuildScreen;
  260. END;
  261. {$IFDEF Linux}
  262. IF Y=7 THEN
  263. BEGIN
  264. write(#27+'(K');
  265. BuildScreen;
  266. END;
  267. {$ENDIF}
  268. END;
  269. END;
  270. IF (X>=(FieldX-2)) AND (Y>=(FieldY-2)) THEN
  271. BEGIN
  272. DEC(X,FieldX-1); DEC(Y,FieldY-1);
  273. X:=X SHR 1;
  274. IF (X<PlayFieldXDimension) AND (Y<PlayFieldYDimension) THEN
  275. BEGIN
  276. IF MarkField[X,Y]<>4 THEN
  277. BEGIN
  278. MarkField:=PlayField;
  279. MarkAfield(X,Y);
  280. DisplayPlayField(MarkField);
  281. TextColor(White);
  282. GotoXY(20,22);
  283. Write(' ':20);
  284. GotoXY(20,22);
  285. Write('Marked :',CubesToScore);
  286. END;
  287. IF (MState AND LButton) <>0 THEN {If leftbutton pressed,}
  288. BEGIN
  289. REPEAT {wait untill it's released.
  290. The moment of pressing counts}
  291. GetMouseState(X,Y,Dummy);
  292. UNTIL (Dummy AND LButton)=0;
  293. Colapse;
  294. MarkField:=PlayField;
  295. DisplayPlayField(MarkField);
  296. END;
  297. END;
  298. END;
  299. IF KeyPressed THEN
  300. BEGIN
  301. X:=GetKey;
  302. IF (X=ORD('X')) OR (X=ORD('x')) THEN
  303. EndOfGame:=2;
  304. END;
  305. END;
  306. UNTIL EndOfGame>0;
  307. ShowScore;
  308. X:=SlipInScore(Score);
  309. IF X<>0 THEN
  310. BEGIN
  311. ShowHighScore;
  312. InputStr(S,HighX,HighY+12-X,10,FALSE,AlfaBeta);
  313. HighScore[X-1].Name:=S;
  314. END;
  315. LastScore:=Score;
  316. UNTIL EndOFGame=2;
  317. END;
  318. CONST FileName='samegame.scr';
  319. VAR I : LONGINT;
  320. BEGIN
  321. IF NOT MousePresent THEN
  322. BEGIN
  323. Writeln('No mouse found. A mouse is required!');
  324. HALT;
  325. END;
  326. FOR I:=1 TO 10 DO
  327. HighScore[I].Score:=I*1500;
  328. LoadHighScore(FileName);
  329. InitMouse;
  330. CursorOff;
  331. HighX:=52; HighY:=10; {the position of the highscore table}
  332. DoMainLoopMouse;
  333. HideMouse;
  334. DoneMouse;
  335. CursorOn;
  336. SaveHighScore;
  337. ClrScr;
  338. Writeln;
  339. Writeln('Last games'#39' score was : ',Score);
  340. END.
  341. {
  342. $Log$
  343. Revision 1.2 1999-06-01 19:24:33 peter
  344. * updates from marco
  345. Revision 1.1 1999/05/27 21:36:34 peter
  346. * new demo's
  347. * fixed mandel for linux
  348. }