fpctris.pp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  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. FPCTris implements a simple Crt driven Tetrisish game to demonstrate the
  6. Crt unit. (KeyPressed, ReadKey, GotoXY, Delay,TextColor,TextBackground)
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. PROGRAM FPCTris;
  14. { Trying to make a tetris from zero as a demo for FPC.
  15. Coordinate system:
  16. 0 -> TheWidth-1 A figure is coded in a LONGINT like this:
  17. ---------
  18. 0 | * | ..*. 00100000 MSB
  19. | | ** | ..*. 00100000
  20. V | * | .**. 01100000
  21. | | .... 00000000 LSB
  22. |+ ++ ++|
  23. |++ ++++++| so 00100000001000000110000000000000b
  24. |+++++++++|
  25. ---------
  26. TheHeight-1
  27. }
  28. Uses Crt,Dos,GameUnit;
  29. {$dEFINE DoubleCache} {Try to write as less characters to console as possible}
  30. CONST TheWidth = 11; {Watch out, also correct RowMask!}
  31. TheHeight = 20;
  32. PosXField = 10; { Upper X,Y coordinates of playfield}
  33. PosYField = 3;
  34. MaxFigures= 16; {Maximum # figures place is reserved for.}
  35. NrLevels = 12; {Number of levels currenty defined}
  36. FieldSpace= 177;
  37. TYPE TetrisFieldType = ARRAY [0..25] OF LONGINT;
  38. LevelInfoType = ARRAY [0..NrLevels-1] OF LONGINT;
  39. FigureType = LONGINT; { actually array[0..3][0..3] of bit rounded up to a longint}
  40. CHARSET = SET OF CHAR;
  41. {The figures: }
  42. CONST GraphFigures : ARRAY[0..4] OF String[80] =(
  43. '.*... .*... .*... ..*.. .*... .*... **... **... ..**. .**.. ..*.. *....',
  44. '.*... .*... .**.. .**.. .*... .**.. **... .*... ..*.. .**.. ..*.. **...',
  45. '**... .**.. ..*.. .*... .*... .*... ..... .*... ..*.. .**.. **.** .**..',
  46. '..... ..... ..... ..... .*... ..... ..... .***. ***.. .**.. ..*.. ..**.',
  47. '..... ..... ..... ..... ..... ..... ..... ..... ..... .**.. ..*.. .....');
  48. {Their relative occurance : }
  49. FigureChance : ARRAY[0..MaxFigures-1] OF LONGINT =(
  50. 8, 8, 8, 8, 8, 8, 10, 1, 1, 1, 1, 1,0,0,0,0 );
  51. {Scores per figure. Not necessarily used. Just for future use}
  52. FigureScore : ARRAY[0..MaxFigures-1] OF LONGINT =(
  53. 2, 2, 4, 4, 1, 2, 2, 10, 10, 10, 20, 10,0,0,0,0 );
  54. {Diverse AND/OR masks to manipulate graphics}
  55. {general table to mask out a bit 31=msb 0=lsb}
  56. AndTable : ARRAY[0..31] OF LONGINT=($80000000,$40000000,$20000000,$10000000,
  57. $8000000,$4000000,$2000000,$1000000,$800000,$400000,$200000,$100000,
  58. $80000,$40000,$20000,$10000,$8000,$4000,$2000,$1000,$800,$400,$200,$100,
  59. $80,$40,$20,$10,8,4,2,1);
  60. {Mask to isolate a row of a (FigureType)}
  61. MagicMasks : ARRAY[0..4] OF LONGINT = ($F8000000,$07C00000,$003E0000,$0001F000,$00000F80);
  62. {Mask to check if a line is full; a bit for every column aligned to left.}
  63. RowMask = $FFE00000;
  64. {Masks to calculate if the left or rightside is partially empty, write them
  65. in binary, and put 5 bits on a row. }
  66. LeftMask : ARRAY[0..4] OF LONGINT = ($84210800,$C6318C00,$E739CE00,$F7BDEF00,$FFFFFFE0);
  67. RightMask: ARRAY[0..4] OF LONGINT = ($08421080,$18C63180,$39CE7380,$7BDEF780,$FFFFFF80);
  68. {Allowed characters entering highscores}
  69. {This constant/parameter is used to detect a certain bug. The bug was fixed, but
  70. I use the constant to remind where the bug was, and what is related to eachother.}
  71. Tune=-1;
  72. {First array is a table to find the level for a given number of dissappeared lines
  73. the second and third are the delaytime and iterationlevel per level. }
  74. LevelBorders : LevelInfoType = ( 10, 20, 30, 45, 60, 80,100,130,160,200,240,280);
  75. DelayLevel : LevelInfoType = (100, 90, 80, 70, 60, 60, 50, 40, 40, 20, 20,10);
  76. IterationLevel: LevelInfoType = ( 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 2, 2);
  77. {Some frequently used chars in high-ascii and low-ascii. UseColor selects between
  78. them}
  79. ColorString = #196#179#192#217#219;
  80. DumbTermStr = '-|..*';
  81. { A multiplication factor to reward killing more then one line with one figure}
  82. ProgressiveFactor : ARRAY[1..5] OF LONGINT = (10,12,16,22,30);
  83. VAR
  84. TopX,TopY : LONGINT; {Coordinates figure relative
  85. to left top of playfield}
  86. FigureNr : LONGINT; {Nr in Figure cache, second
  87. index in Figures}
  88. {$IFDEF DoubleCache}
  89. BackField, {Copy of the screen for faster matching}
  90. {$ENDIF}
  91. MainField : TetrisFieldType; {The screen grid}
  92. ColorField : ARRAY[0..TheHeight-1,0..TheWidth-1] OF LONGINT; {The color info}
  93. DelayTime : LONGINT; {Delay time, can be used for
  94. implementing levels}
  95. IterationPerDelay : LONGINT; {Iterations of mainloop (incl delay)
  96. before the piece falls down a row}
  97. TotalChance : LONGINT; {Sum of FigureChange array}
  98. Lines : LONGINT; {Completed lines}
  99. NrFigures : LONGINT; {# Figures currently used}
  100. RightSizeArray, {Nunber of empty columns to the left }
  101. LeftSizeArray, {or right of the figure/piece}
  102. Figures : ARRAY[0..MaxFigures-1,0..3] OF LONGINT; {All bitmap info of figures}
  103. NrFiguresLoaded : LONGINT; {Total figures available in GraphFigures}
  104. CurrentCol : LONGINT; {Color of current falling piece}
  105. UseColor : BOOLEAN; {Color/Mono mode}
  106. Level : LONGINT; {The current level number}
  107. Style : String; {Contains all chars to create the field}
  108. nonupdatemode : BOOLEAN; {Helpmode/highscore screen or game mode}
  109. HelpMode : BOOLEAN;
  110. NextFigure : LONGINT; {Next figure to fall}
  111. Score : LONGINT; {The score}
  112. FUNCTION RRotate(Figure:FigureType;ColumnsToDo:LONGINT):FigureType;
  113. {Rotate a figure to the right (=clockwise).
  114. This new (v0.06) routine performs a ColumnsTodo x ColumnsToDo rotation,
  115. instead of always a 4x4 (v0.04) or 5x5 (v0.05) rotation.
  116. This avoids weird, jumpy behaviour when rotating small pieces.}
  117. VAR I,J, NewFig:LONGINT;
  118. BEGIN
  119. NewFig:=0;
  120. FOR I:=0 TO ColumnsToDo-1 DO
  121. FOR J:=0 TO ColumnsToDo-1 DO
  122. IF Figure AND AndTable[I*5+J]<>0 THEN
  123. NewFig:=NewFig OR AndTable[(ColumnsToDo-1-I)+5*(J)]; {}
  124. RRotate:=NewFig;
  125. END;
  126. { LeftSize and RightSize count the number of empty lines to the left and
  127. right of the character. On the below character LeftSize will return 2 and
  128. RightSize will return 1.
  129. ..*.
  130. ..*.
  131. ..*.
  132. ..*.
  133. }
  134. FUNCTION RightSize(Fig:FigureType):LONGINT;
  135. VAR I : LONGINT;
  136. BEGIN
  137. I:=0;
  138. WHILE ((Fig AND RightMask[I])=0) AND (I<5) DO
  139. INC(I);
  140. IF I>4 THEN
  141. HALT;
  142. Rightsize:=I;
  143. END;
  144. FUNCTION Leftsize(Fig:FigureType):LONGINT;
  145. VAR I : LONGINT;
  146. BEGIN
  147. I:=0;
  148. WHILE ((Fig AND LeftMask[I])=0) AND (I<5) DO
  149. INC(I);
  150. IF I>4 THEN
  151. HALT;
  152. Leftsize:=I;
  153. END;
  154. FUNCTION FigSym(Figure:LONGINT;RightSizeFig:LONGINT):LONGINT;
  155. {Try to find the "symmetry" of a figure, the smallest square (1x1,2x2,3x3 etc)
  156. in which the figure fits. This requires all figures designed to be aligned to
  157. topleft.}
  158. VAR ColumnsToDo : LONGINT;
  159. BEGIN
  160. {Determine which bottom rows aren't used}
  161. ColumnsToDo:=5;
  162. WHILE ((Figure AND MagicMasks[ColumnsToDo-1])=0) AND (ColumnsToDo>1) DO
  163. DEC(ColumnsToDo);
  164. {Compare with columns used, already calculated, and take the biggest}
  165. IF ColumnsToDo<(5-RightSizeFig) THEN
  166. ColumnsToDo:=5-RightSizeFig;
  167. FigSym:=ColumnsToDo;
  168. END;
  169. PROCEDURE CreateFiguresArray;
  170. {Reads figures from ASCII representation into binary form, and creates the
  171. rotated representations, and the number of empty columns to the right and
  172. left per figure. }
  173. VAR I,J,K,L,Symmetry : LONGINT;
  174. BEGIN
  175. NrFigures:=0; K:=1;
  176. WHILE K<Length(GraphFigures[0]) DO
  177. BEGIN
  178. IF GraphFigures[0][K]=' ' THEN
  179. INC(K);
  180. L:=0;
  181. FOR I:=0 TO 4 DO {Rows}
  182. FOR J:=0 TO 4 DO {Columns}
  183. IF GraphFigures[I][K+J]='*' THEN
  184. L:=L OR AndTable[I*5+J];
  185. Figures[NrFigures][0]:=L;
  186. INC(NrFigures);
  187. INC(K,5);
  188. END;
  189. NrFiguresLoaded:=NrFigures;
  190. FOR I:= 0 TO NrFigures-1 DO
  191. BEGIN
  192. RightSizeArray[I][0]:=RightSize(Figures[I][0]);
  193. LeftSizeArray[I][0]:=LeftSize(Figures[I][0]);
  194. Symmetry:=FigSym(Figures[I][0],RightSizeArray[I][0]);
  195. FOR J:=0 TO 2 DO {Create the other 3 by rotating}
  196. BEGIN
  197. Figures[I][J+1]:=RRotate(Figures[I][J],Symmetry);
  198. RightSizeArray[I][J+1]:=RightSize(Figures[I][J+1]);
  199. LeftSizeArray[I][J+1]:=LeftSize(Figures[I][J+1]);
  200. END;
  201. END;
  202. {Clear main grid}
  203. FillChar(MainField,SIZEOF(TetrisFieldType),0);
  204. END;
  205. PROCEDURE CalculateTotalChance;
  206. {Called after a change in the the number of figures, normally 7 (standard)
  207. or NrFiguresLoaded (10 right now) to recalculate the total of the chance table}
  208. VAR Temp:LONGINT;
  209. BEGIN
  210. TotalChance:=0;
  211. FOR Temp:=0 TO NrFigures-1 DO INC(TotalChance,FigureChance[Temp]);
  212. END;
  213. FUNCTION MatchPosition(Fig:FigureType;X,Y:LONGINT): BOOLEAN;
  214. {Most important routine. Tries to position the figure on the position
  215. IF it returns FALSE then the piece overlaps something on the background,
  216. or the lower limit of the playfield
  217. }
  218. VAR I,J,K : LONGINT;
  219. Match: BOOLEAN;
  220. BEGIN
  221. Match:=TRUE;
  222. FOR I:=0 TO 4 DO
  223. BEGIN
  224. K:=Fig;
  225. K:=K AND MagicMasks[I];
  226. IF K<>0 THEN
  227. BEGIN
  228. J:=5*(I)-X+Tune;
  229. IF J>0 THEN
  230. K:=K SHL J
  231. ELSE
  232. IF J<0 THEN
  233. K:=K SHR -J;
  234. IF (MainField[Y+I] AND K)<>0 THEN
  235. Match:=FALSE;
  236. END;
  237. END;
  238. I:=4;
  239. IF (Fig AND MagicMasks[4])=0 THEN
  240. DEC(I);
  241. IF (Fig AND MagicMasks[3])=0 THEN
  242. DEC(I);
  243. IF (Fig AND MagicMasks[2])=0 THEN
  244. DEC(I);
  245. IF (Y+I)>=TheHeight THEN
  246. Match:=FALSE;
  247. MatchPosition:=Match;
  248. END;
  249. PROCEDURE FixFigureInField(Fig:FigureType;X,Y:LONGINT;Clear:BOOLEAN);
  250. {Blends the figure into the background, or erases the figure from the
  251. background}
  252. VAR I,J,K : LONGINT;
  253. BEGIN
  254. FOR I:=0 TO 4 DO
  255. BEGIN
  256. K:=Fig;
  257. K:=K AND MagicMasks[I];
  258. IF K<>0 THEN
  259. BEGIN
  260. J:=5*I-X+Tune;
  261. IF J>0 THEN
  262. K:=K SHL J
  263. ELSE
  264. IF J<0 THEN
  265. K:=K SHR (-J);
  266. IF Clear THEN
  267. BEGIN
  268. K:=K XOR -1;
  269. MainField[Y+I]:= MainField[Y+I] AND K;
  270. END
  271. ELSE
  272. MainField[Y+I]:= MainField[Y+I] OR K;
  273. END;
  274. END;
  275. END;
  276. PROCEDURE FixColField(ThisFig:LONGINT);
  277. {Puts color info of a figure into the colorgrid, simplified
  278. FixFigureInField on byte instead of bit manipulation basis.}
  279. VAR I,J,K : LONGINT;
  280. BEGIN
  281. FOR I:=0 TO 4 DO
  282. BEGIN
  283. K:=Figures[ThisFig][FigureNr];
  284. IF (I+TopY)<=TheHeight THEN
  285. FOR J:=0 TO 4 DO
  286. BEGIN
  287. IF (K AND AndTable[J+5*I])<>0 THEN
  288. ColorField[TopY+I,TopX-Tune+J]:=CurrentCol;
  289. END;
  290. END;
  291. END;
  292. PROCEDURE DisplMainFieldTextMono;
  293. {Displays the grid with a simple buffering algoritm, depending on
  294. conditional DoubleBuffer}
  295. VAR Row,Column,Difference,StartRow,EndRow : LONGINT;
  296. S : String;
  297. BEGIN
  298. FOR Row:=0 TO TheHeight-1 DO
  299. BEGIN
  300. {$IFDEF DoubleCache}
  301. IF BackField[Row]<>MainField[Row] THEN
  302. BEGIN
  303. {$ENDIF}
  304. FillChar(S[1],2*TheWidth,#32);
  305. StartRow:=0;
  306. EndRow:=TheWidth-1;
  307. {$IFDEF DoubleCache}
  308. Difference:=MainField[Row] XOR BackField[Row]; {Calc differences in line}
  309. {Search for first and last bit changed}
  310. WHILE ((Difference AND AndTable[StartRow])=0) AND (StartRow<(TheWidth-1)) DO
  311. INC(StartRow);
  312. WHILE ((Difference AND AndTable[EndRow])=0) AND (EndRow>0) DO
  313. DEC(EndRow);
  314. {$ENDIF}
  315. {Prepare a string}
  316. GotoXY(PosXField+2*StartRow,PosYField+Row);
  317. S[0]:=CHR(2*(EndRow-StartRow+1));
  318. FOR Column:=0 TO EndRow-StartRow DO
  319. BEGIN
  320. IF (MainField[Row] AND AndTable[StartRow+Column])<>0 THEN
  321. BEGIN
  322. S[Column*2+1]:=Style[5];
  323. S[Column*2+2]:=Style[5];
  324. END;
  325. END;
  326. {Write the string}
  327. Write(S);
  328. {$IFDEF DoubleCache}
  329. END;
  330. {$ENDIF}
  331. END;
  332. {$IFDEF DoubleCache}
  333. BackField:=MainField; {Keep a copy of the screen for faster updates
  334. of terminals, for next DisplMainFieldText.}
  335. {$ENDIF}
  336. END;
  337. PROCEDURE DisplMainFieldTextColor;
  338. {Same as above, but also use ColorField to output colors,
  339. the buffering is the same, but the colors make it less efficient.}
  340. VAR Row,Column,Difference,StartRow,EndRow,
  341. L : LONGINT;
  342. S : String;
  343. LastCol : LONGINT;
  344. BEGIN
  345. LastCol:=255;
  346. FOR Row:=0 TO TheHeight-1 DO
  347. BEGIN
  348. {$IFDEF DoubleCache}
  349. IF BackField[Row]<>MainField[Row] THEN
  350. BEGIN
  351. {$ENDIF}
  352. FillChar(S[1],2*TheWidth,#32);
  353. StartRow:=0;
  354. EndRow:=TheWidth-1;
  355. {$IFDEF DoubleCache}
  356. Difference:=MainField[Row] XOR BackField[Row]; {Calc differences in line}
  357. WHILE ((Difference AND AndTable[StartRow])=0) AND (StartRow<(TheWidth-1)) DO
  358. INC(StartRow);
  359. WHILE ((Difference AND AndTable[EndRow])=0) AND (EndRow>0) DO
  360. DEC(EndRow);
  361. {$ENDIF}
  362. GotoXY(PosXField+2*StartRow,PosYField+Row);
  363. FOR Column:=0 TO EndRow-StartRow DO
  364. BEGIN
  365. IF (MainField[Row] AND AndTable[StartRow+Column])<>0 THEN
  366. BEGIN
  367. L:=ColorField[Row,StartRow+Column];
  368. IF L=0 THEN
  369. L:=CurrentCol;
  370. IF L<>LastCol THEN
  371. BEGIN
  372. TextColor(L);
  373. Write(Style[5],Style[5]);
  374. END;
  375. END
  376. ELSE
  377. Write(' ');
  378. END;
  379. {$IFDEF DoubleCache}
  380. END;
  381. {$ENDIF}
  382. END;
  383. {$IFDEF DoubleCache}
  384. BackField:=MainField; {Keep a copy of the screen for faster updates
  385. of terminals, for next DisplMainFieldText.}
  386. {$ENDIF}
  387. END;
  388. PROCEDURE DisplMainFieldText;
  389. {Main redraw routine; Check in what mode we are and call appropriate routine}
  390. BEGIN
  391. IF UseColor THEN
  392. DisplMainFieldTextColor
  393. ELSE
  394. DisplMainFieldTextMono;
  395. END;
  396. PROCEDURE RedrawScreen;
  397. {Frustrates the caching system so that the entire screen is redrawn}
  398. VAR I : LONGINT;
  399. BEGIN
  400. FOR I:=0 TO TheHeight-1 DO
  401. BackField[I]:=MainField[I] XOR -1; {backup copy is opposite of MainField}
  402. END;
  403. FUNCTION GetNextFigure:LONGINT;
  404. VAR IndTotal,Temp,TheFigure : LONGINT;
  405. BEGIN
  406. Temp:=RANDOM(TotalChance);
  407. IndTotal:=0;
  408. TheFigure:=0;
  409. WHILE Temp>=IndTotal DO
  410. BEGIN
  411. INC(IndTotal,FigureChance[TheFigure]);
  412. INC(TheFigure);
  413. END;
  414. dec(thefigure);
  415. GetNextFigure:=TheFigure;
  416. END;
  417. PROCEDURE ShowNextFigure(ThisFig:LONGINT);
  418. VAR I,J,K : LONGINT;
  419. S : String[8];
  420. BEGIN
  421. IF UseColor THEN
  422. TextColor(White);
  423. IF NOT nonupdatemode THEN
  424. BEGIN
  425. FOR I:=0 TO 4 DO
  426. BEGIN
  427. FillChar(S,9,' ');
  428. S[0]:=#8;
  429. K:=Figures[ThisFig][FigureNr];
  430. IF (I+TopY)<=TheHeight THEN
  431. FOR J:=0 TO 4 DO
  432. BEGIN
  433. IF (K AND AndTable[J+5*I])<>0 THEN
  434. BEGIN
  435. S[J*2+1]:=Style[5];
  436. S[J*2+2]:=Style[5];
  437. END
  438. END;
  439. GotoXY(50,11+I); Write(S);
  440. END;
  441. END;
  442. END;
  443. PROCEDURE FixScores;
  444. BEGIN
  445. IF UseColor THEN
  446. SetDefaultColor;
  447. GotoXY(40,18);
  448. Write('Score :',Score);
  449. END;
  450. PROCEDURE ShowLines;
  451. BEGIN
  452. IF NOT nonupdatemode THEN
  453. BEGIN
  454. IF UseColor THEN
  455. TextColor(Yellow);
  456. GotoXY(40,16); Write('Lines: ',Lines:4,' Level: ',Level);
  457. END;
  458. END;
  459. FUNCTION InitAFigure(VAR TheFigure:LONGINT) : BOOLEAN;
  460. {A new figure appears in the top of the screen. If return value=FALSE then
  461. the piece couldn't be created (when it is overlapping with the background.
  462. That's the game-over condition)}
  463. VAR Temp : LONGINT;
  464. BEGIN
  465. TopX:=(TheWidth-4) DIV 2; { Middle of Screen}
  466. TopY:=0;
  467. FigureNr:=1;
  468. IF TheFigure<>-1 THEN
  469. INC(Score,FigureScore[TheFigure]);
  470. IF NOT NonUpdateMode THEN
  471. FixScores;
  472. Temp:=GetNextFigure; {Determine next char (after the one this
  473. initafigure created has got down)}
  474. TheFigure:=NextFigure; {Previous NextFigure becomes active now.}
  475. NextFigure:=Temp;
  476. InitAFigure:=MatchPosition(Figures[TheFigure][0],TopX,TopY);
  477. ShowNextFigure(NextFigure);
  478. CurrentCol:=RANDOM(14)+1;
  479. END;
  480. {
  481. PROCEDURE ShowHighScore;
  482. VAR I : LONGINT;
  483. BEGIN
  484. GotoXY(50,9); Write('The Highscores');
  485. FOR I:=0 TO 9 DO
  486. BEGIN
  487. GotoXY(40,20-I);
  488. Write(HighScore[I].Name,' ':(13-Length(HighScore[I].Name)),' ',HighScore[I].Score:5);
  489. END;
  490. END;
  491. }
  492. PROCEDURE ShowGameMode;
  493. BEGIN
  494. IF NOT nonupdatemode THEN
  495. BEGIN
  496. GotoXY(61,13);
  497. IF NrFigures<>7 THEN
  498. write('Extended')
  499. ELSE
  500. write('Standard');
  501. END;
  502. END;
  503. PROCEDURE CreateFrame;
  504. {Used once to print the "background" of the screen (not the background grid,
  505. but the text, and the cadre around the playfield}
  506. VAR I : LONGINT;
  507. BEGIN
  508. SetDefaultColor;
  509. GotoXY(40,4);
  510. Write('FPCTris v0.07, (C) by the FPC team.');
  511. GotoXY(40,6);
  512. Write('A demo of the FPC Crt unit, and');
  513. GotoXY(40,7);
  514. Write(' its portability');
  515. FOR I:=9 TO 24 DO
  516. BEGIN
  517. GotoXY(40,I);
  518. Write(' ':38);
  519. END;
  520. ShowGameMode;
  521. IF nonupdatemode THEN
  522. BEGIN
  523. IF HelpMode THEN
  524. BEGIN
  525. GotoXY(40,9);
  526. Write('Arrow left/right to move, down to drop');
  527. GotoXY(40,10);
  528. Write('arrow-up to rotate the piece');
  529. GotoXY(40,11);
  530. Write('"P" to pause');
  531. GotoXY(40,12);
  532. Write('"E" Mode (standard or extended)');
  533. GotoXY(40,13);
  534. Write('"C" switches between color/mono mode');
  535. GotoXY(40,14);
  536. Write('Escape to quit');
  537. GotoXY(40,15);
  538. Write('"S" to show the highscores');
  539. {$IFDEF Linux}
  540. GotoXY(40,16);
  541. Write('"i" try to switch to IBM character set');
  542. {$ENDIF}
  543. END
  544. ELSE
  545. ShowHighScore;
  546. END
  547. ELSE
  548. BEGIN
  549. GotoXY(40,9);
  550. Write('"h" to display the helpscreen');
  551. END;
  552. FOR I :=0 TO TheHeight-1 DO
  553. BEGIN
  554. GotoXY(PosXField-1 ,PosYField+I); Write(Style[2]);
  555. GotoXY(PosXField+2*TheWidth ,PosYField+I); Write(Style[2]);
  556. END;
  557. GotoXY(PosXField-1,PosYField+TheHeight);
  558. Write(Style[3]);
  559. FOR I:=0 TO (2*TheWidth)-1 DO
  560. Write(Style[1]);
  561. Write(Style[4]);
  562. END;
  563. PROCEDURE FixLevel(Lines:LONGINT);
  564. BEGIN
  565. Level:=0;
  566. WHILE (Lines>LevelBorders[Level]) AND (Level<HIGH(LevelBorders)) DO
  567. INC(Level);
  568. DelayTime:=DelayLevel[Level];
  569. IterationPerDelay:=IterationLevel[Level];
  570. END;
  571. PROCEDURE FixMainFieldLines;
  572. {Deletes full horizontal lines from the playfield will also get some
  573. score-keeping code in the future.}
  574. VAR I,LocalLines : LONGINT;
  575. BEGIN
  576. I:=TheHeight-1;
  577. LocalLines:=0;
  578. WHILE I>=0 DO
  579. BEGIN
  580. IF (MainField[I] XOR RowMask)=0 THEN
  581. BEGIN
  582. Move(MainField[0],MainField[1],I*4);
  583. Move(ColorField[0,0],ColorField[1,0],4*I*TheWidth);
  584. MainField[0]:=0;
  585. FillChar(ColorField[0,0],0,TheWidth);
  586. INC(LocalLines);
  587. END
  588. ELSE
  589. DEC(I);
  590. END;
  591. INC(Lines,LocalLines);
  592. INC(Score,ProgressiveFactor[LocalLines]*LocalLines);
  593. I:=Level;
  594. FixLevel(Lines);
  595. IF LocalLines<>0 THEN
  596. ShowLines;
  597. {$IFDEF DoubleCache}
  598. IF UseColor THEN
  599. RedrawScreen;
  600. {$ENDIF}
  601. END;
  602. PROCEDURE DoFPCTris;
  603. {The main routine. Initialisation, keyboard loop}
  604. VAR EndGame : BOOLEAN;
  605. FixHickup : LONGINT;
  606. Counter : LONGINT;
  607. Temp,Key : LONGINT;
  608. TheFigure : LONGINT; {Current first index in Figures}
  609. PROCEDURE TurnFigure;
  610. {Erases a figure from the grid, turns it if possible, and puts it back on
  611. again}
  612. BEGIN
  613. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,TRUE);
  614. IF MatchPosition(Figures[TheFigure][Temp],TopX,TopY) THEN
  615. FigureNr:=Temp;
  616. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  617. END;
  618. PROCEDURE FixHighScores;
  619. VAR I,J : LONGINT;
  620. S : String;
  621. BEGIN
  622. FOR J:=9 TO 22 DO
  623. BEGIN
  624. GotoXY(40,J);
  625. Write(' ':38);
  626. END;
  627. IF UseColor THEN
  628. TextColor(White);
  629. GotoXY(40,23);
  630. Writeln('Game Over, score = ',Score);
  631. I:=SlipInScore(Score);
  632. IF I<>0 THEN
  633. BEGIN
  634. NonUpdateMode:=TRUE;
  635. HelpMode:=FALSE;
  636. ShowHighScore;
  637. InputStr(S,40,21-I,10,FALSE,AlfaBeta);
  638. HighScore[I-1].Name:=S;
  639. END;
  640. ShowHighScore;
  641. END;
  642. {$IFNDEF FPC}
  643. PROCEDURE SetCursorSize(CurDat:WORD);ASSEMBLER;
  644. ASM
  645. mov ah,1
  646. mov cx,CurDat
  647. int $10
  648. END;
  649. {The two procedures below are standard (and os-independant) in FPC's Crt}
  650. PROCEDURE CursorOn;
  651. BEGIN
  652. SetCursorSize($090A);
  653. END;
  654. PROCEDURE CursorOff;
  655. BEGIN
  656. SetCursorSize($FFFF);
  657. END;
  658. {$ENDIF}
  659. BEGIN
  660. {Here should be some terminal-detection for Linux}
  661. nonupdatemode:=FALSE;
  662. HelpMode :=TRUE;
  663. {$IFDEF Linux}
  664. UseColor:=FALSE;
  665. {$ELSE}
  666. UseColor:=TRUE;
  667. {$ENDIF}
  668. ClrScr;
  669. CursorOff;
  670. RANDOMIZE;
  671. HighX:=40;
  672. HighY:=9;
  673. CreateFiguresArray; { Load and precalculate a lot of stuff}
  674. IF UseColor THEN
  675. Style:= ColorString
  676. ELSE
  677. Style:=DumbTermStr;
  678. NrFigures:=7; {Default standard tetris mode, only use
  679. the first 7 standard figures}
  680. CalculateTotalChance; {Calculated the total of all weightfactors}
  681. EndGame:=FALSE; {When TRUE, end of game has been detected}
  682. FixHickup:=0; {Used to avoid unnecessary pauses with the "down key"}
  683. CreateFrame; {Draws all background garbadge}
  684. TheFigure:=-1;
  685. NextFigure:=GetNextFigure; {Two figures have to be inited. The first
  686. figure starts dropping, and that is this
  687. one}
  688. InitAFigure(TheFigure); {The second figure is the figure to be
  689. displayed as NEXT. That's this char :-)}
  690. DisplMainFieldText; {Display/update the grid}
  691. Counter:=0; {counts up to IterationPerDelay}
  692. DelayTime:=100; {Time of delay}
  693. IterationPerDelay:=5; {= # Delays per shift down of figure}
  694. Lines:=0; {Lines that have disappeared}
  695. Score:=0;
  696. ShowLines;
  697. REPEAT
  698. IF KeyPressed THEN {The function name says it all}
  699. BEGIN
  700. Key:=ORD(READKEY);
  701. IF Key=0 THEN {Function key?}
  702. Key:=ORD(READKEY) SHL 8;
  703. CASE Key OF {Check for all keys}
  704. ArrU : BEGIN
  705. Temp:=(FigureNr+3) AND 3;
  706. IF ((TopX+LeftSizeArray[TheFigure][FigureNr])<0) THEN
  707. BEGIN
  708. IF (LeftSizeArray[TheFigure][FigureNr]<=LeftSizeArray[TheFigure][Temp]) THEN
  709. TurnFigure;
  710. END
  711. ELSE
  712. IF (TopX+7-RightSizeArray[TheFigure][FigureNr])>TheWidth THEN
  713. BEGIN
  714. IF (RightSizeArray[TheFigure][FigureNr]<=RightSizeArray[TheFigure][Temp]) THEN
  715. TurnFigure;
  716. END
  717. ELSE
  718. TurnFigure;
  719. END;
  720. ArrL : BEGIN
  721. IF (TopX+LeftSizeArray[TheFigure][FigureNr])>=0 THEN
  722. BEGIN
  723. Temp:=TopX+1-LeftSizeArray[TheFigure][FigureNr];
  724. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,TRUE);
  725. IF MatchPosition(Figures[TheFigure][FigureNr],TopX-1,TopY) THEN
  726. DEC(TopX);
  727. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  728. END;
  729. END;
  730. ArrR : BEGIN
  731. IF (TopX+7-RightSizeArray[TheFigure][FigureNr])<=TheWidth THEN
  732. BEGIN
  733. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,TRUE);
  734. IF MatchPosition(Figures[TheFigure][FigureNr],TopX+1,TopY) THEN
  735. INC(TopX);
  736. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  737. END;
  738. END;
  739. ArrD : BEGIN
  740. IF FixHickup=0 THEN
  741. BEGIN
  742. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,TRUE);
  743. Temp:=TopY;
  744. WHILE MatchPosition(Figures[TheFigure][FigureNr],TopX,TopY+1) DO
  745. INC(TopY);
  746. Temp:=TopY-Temp;
  747. INC(Score,Temp DIV 2);
  748. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  749. FixHickUp:=4;
  750. END;
  751. END;
  752. ORD('q'),
  753. ESC : BEGIN
  754. SetDefaultColor;
  755. GotoXY(1,25);
  756. EndGame:=TRUE;
  757. END;
  758. ORD('C'),
  759. ORD('c') : BEGIN
  760. UseColor:=NOT UseColor;
  761. IF UseColor THEN
  762. Style:= ColorString
  763. ELSE
  764. BEGIN
  765. SetDefaultColor;
  766. Style:=DumbTermStr;
  767. END;
  768. CreateFrame;
  769. RedrawScreen;
  770. DisplMainFieldText;
  771. END;
  772. ORD('H'),
  773. ORD('h') : BEGIN
  774. nonupdatemode:=NOT nonupdatemode;
  775. CreateFrame;
  776. ShowLines;
  777. ShowNextFigure(NextFigure);
  778. END;
  779. ORD('S'),
  780. ORD('s') : BEGIN
  781. IF NOT nonupdatemode THEN
  782. BEGIN
  783. NonUpdateMode:=TRUE;
  784. helpmode:=NOT helpmode;
  785. END
  786. ELSE
  787. HelpMode:=NOT helpmode;
  788. CreateFrame;
  789. ShowLines;
  790. ShowNextFigure(NextFigure);
  791. END;
  792. ORD('E'),
  793. ORD('e'): BEGIN {Extra figures on/off}
  794. IF NrFigures<>NrFiguresLoaded THEN
  795. NrFigures:=NrFiguresLoaded {Extra figures}
  796. ELSE
  797. NrFigures:=7; {Standard Tetris figures}
  798. CalculateTotalChance; {Recalculate weight-totals}
  799. IF UseColor THEN
  800. SetDefaultColor;
  801. ShowGameMode;
  802. END;
  803. ORD('p') : BEGIN {"p" : Pause}
  804. Key:=ORD(ReadKey);
  805. IF Key=0 THEN
  806. Key:=ORD(ReadKey);
  807. END;
  808. {$IFDEF Linux}
  809. ORD('i') : write(#27+'(K');
  810. {$ENDIF}
  811. END; {END OF Key CASE}
  812. END { OF If KeyPressed}
  813. ELSE
  814. BEGIN
  815. {$IFDEF Linux}
  816. GotoXY(50,10); {Get cursor out of the way, CursorOn/Off
  817. doesn't work on telnet-terminals}
  818. {$ENDIF}
  819. Delay(DelayTime);
  820. END;
  821. INC(Counter);
  822. IF (Counter=IterationPerDelay) OR (FixHickup=1) THEN
  823. BEGIN
  824. IF FixHickup=1 THEN
  825. Counter:=IterationPerDelay-1
  826. ELSE
  827. Counter:=0;
  828. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,TRUE);
  829. FixHickup:=0;
  830. IF MatchPosition(Figures[TheFigure][FigureNr],TopX,TopY+1) THEN
  831. BEGIN
  832. INC(TopY);
  833. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  834. END
  835. ELSE
  836. BEGIN
  837. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  838. FixColField(TheFigure);
  839. IF InitAFigure(TheFigure) THEN
  840. BEGIN
  841. FixMainFieldLines;
  842. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  843. DisplMainFieldText;
  844. Delay(DelayTime*IterationPerDelay);
  845. END
  846. ELSE
  847. BEGIN
  848. FixFigureInField(Figures[TheFigure][FigureNr],TopX,TopY,FALSE);
  849. EndGame:=TRUE;
  850. END;
  851. END;
  852. END
  853. ELSE
  854. IF FixHickup>1 THEN
  855. DEC(FixHickup);
  856. DisplMainFieldText;
  857. UNTIL EndGame;
  858. FixHighScores;
  859. CursorOn;
  860. SetDefaultColor;
  861. GotoXY(1,25);
  862. END;
  863. CONST FileName='fpctris.scr';
  864. VAR I : LONGINT;
  865. BEGIN
  866. FOR I:=0 TO 9 DO
  867. HighScore[I].Score:=(I+1)*750;
  868. LoadHighScore(FileName);
  869. DoFpcTris;
  870. SaveHighScore;
  871. END.
  872. {
  873. $Log$
  874. Revision 1.2 1999-06-01 19:24:32 peter
  875. * updates from marco
  876. Revision 1.1 1999/05/27 21:36:33 peter
  877. * new demo's
  878. * fixed mandel for linux
  879. }