VNCTetrisServer.Mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. MODULE VNCTetrisServer; (** AUTHOR "TF"; PURPOSE "VNC Tetris server"; *)
  2. (** old aged *)
  3. IMPORT Raster, KernelLog, Commands, Kernel, Random, VNCServer, WMRectangles,
  4. WMGraphics, Inputs, Modules, Files, IP, Dates, Strings;
  5. CONST
  6. Width = 10;
  7. Height = 30;
  8. BoxSize = 16;
  9. BlockSize = 5;
  10. NofBlocks = 7;
  11. ScoreHeight = 108;
  12. DataFile = "VNCTetris.dat";
  13. VAR colors : ARRAY NofBlocks + 1 OF Raster.Pixel;
  14. gamesRunning, gamesTotal, maxConcurrent, highScore : LONGINT;
  15. shuttingDown : BOOLEAN;
  16. server: VNCServer.Server;
  17. TYPE
  18. Block = ARRAY BlockSize, BlockSize OF CHAR;
  19. TimeDate = RECORD h, m, s, day,month,year: LONGINT END;
  20. TT = OBJECT
  21. VAR
  22. alive, dropped : BOOLEAN;
  23. field : ARRAY Width OF ARRAY Height OF CHAR;
  24. block : Block;
  25. posX, posY : LONGINT;
  26. timer : Kernel.Timer;
  27. mode : Raster.Mode;
  28. random : Random.Generator;
  29. lines, blocks, delay, delayDec: LONGINT;
  30. img : Raster.Image;
  31. paused, run: BOOLEAN;
  32. cheated: LONGINT;
  33. time : TimeDate;
  34. adrStr, timeStr:ARRAY 32 OF CHAR;
  35. vncInfo : VNCServer.VNCInfo;
  36. canvas : WMGraphics.BufferCanvas;
  37. PROCEDURE &Create*(vncInfo : VNCServer.VNCInfo);
  38. BEGIN
  39. NEW(img);
  40. Raster.Create(img, Width * BoxSize, Height * BoxSize + ScoreHeight, Raster.BGR565);
  41. Raster.InitMode(mode, Raster.srcCopy); NEW(timer); NEW(random); random.InitSeed(Kernel.GetTicks()); lines := 0;
  42. NEW(canvas, img);
  43. SELF.vncInfo := vncInfo;
  44. run := FALSE
  45. END Create;
  46. PROCEDURE Run;
  47. BEGIN {EXCLUSIVE}
  48. run := TRUE
  49. END Run;
  50. PROCEDURE Bound(VAR x:LONGINT; min, max:LONGINT);
  51. BEGIN IF x<min THEN x:=min ELSE IF x>max THEN x:=max END END
  52. END Bound;
  53. PROCEDURE ClipAtImage(VAR x: WMRectangles.Rectangle; img:Raster.Image);
  54. BEGIN
  55. Bound(x.l, 0, img.width);Bound(x.r, 0, img.width);
  56. Bound(x.t, 0, img.height);Bound(x.b, 0, img.height)
  57. END ClipAtImage;
  58. PROCEDURE AddDirty(l, t, r, b:LONGINT);
  59. VAR x: WMRectangles.Rectangle;
  60. BEGIN
  61. WMRectangles.SetRect(x, l, t, r, b);
  62. ClipAtImage(x, img);
  63. IF vncInfo.agent # NIL THEN vncInfo.agent.AddDirty(x) END
  64. END AddDirty;
  65. PROCEDURE Close;
  66. BEGIN
  67. alive := FALSE
  68. END Close;
  69. PROCEDURE RotateBlock(VAR block:Block):Block;
  70. VAR i, j : INTEGER; temp : Block;
  71. BEGIN
  72. FOR i := 0 TO BlockSize - 1 DO FOR j := 0 TO BlockSize - 1 DO temp[j, i] := block[(BlockSize - 1) - i, j] END END;
  73. RETURN temp
  74. END RotateBlock;
  75. PROCEDURE DrawBox(x, y: LONGINT; color: CHAR);
  76. VAR pix : Raster.Pixel;
  77. BEGIN
  78. pix := colors [ORD(color)];
  79. IF (x >= 0) & (x < Width) & (y >= 0) & (y < Height) THEN
  80. Raster.Fill(img, x * BoxSize, y * BoxSize, x * BoxSize+ BoxSize, y * BoxSize + BoxSize, pix, mode)
  81. END;
  82. END DrawBox;
  83. PROCEDURE SetBlock(x, y : LONGINT; clear : BOOLEAN);
  84. VAR i, j : LONGINT;
  85. BEGIN
  86. FOR i := 0 TO BlockSize - 1 DO FOR j := 0 TO BlockSize - 1 DO
  87. IF block[i, j] # 0X THEN
  88. IF (i + x < Width) & (j + y >= 0) & (j + y < Height) THEN
  89. IF clear THEN
  90. field[i + x, j + y] := 0X;
  91. DrawBox(i + x, j + y, 0X)
  92. ELSE field[i + x, j + y] := block[i, j];
  93. DrawBox(i + x, j + y, block[i, j])
  94. END
  95. END
  96. END
  97. END END
  98. END SetBlock;
  99. PROCEDURE HasDownCollision(x, y: LONGINT) : BOOLEAN;
  100. VAR i, j : LONGINT;
  101. BEGIN
  102. FOR i := 0 TO BlockSize - 1 DO FOR j := 0 TO BlockSize - 1 DO
  103. IF block[i, j] # 0X THEN
  104. IF (i + x < Width) & (j + y >= 0) THEN
  105. IF (j + y < Height) THEN
  106. IF (block[i, j] # 0X) & (field[i + x, j + y] # 0X) THEN RETURN TRUE END
  107. ELSIF block[i, j] # 0X THEN RETURN TRUE
  108. END
  109. ELSE RETURN TRUE
  110. END
  111. END
  112. END END;
  113. RETURN FALSE
  114. END HasDownCollision;
  115. PROCEDURE HasCollision(VAR bl: Block; x, y: LONGINT) : BOOLEAN;
  116. VAR i, j : LONGINT;
  117. BEGIN
  118. FOR i := 0 TO BlockSize - 1 DO FOR j := 0 TO BlockSize - 1 DO
  119. IF bl[i, j] # 0X THEN
  120. IF (i + x >= Width) OR (i + x < 0) OR (j + y >= Height) OR (field[i + x, j + y] # 0X) THEN RETURN TRUE END
  121. END
  122. END END;
  123. RETURN FALSE
  124. END HasCollision;
  125. PROCEDURE Move(dir: LONGINT):BOOLEAN;
  126. VAR newX, newY: LONGINT; result : BOOLEAN;
  127. BEGIN
  128. newX := posX; newY := posY;
  129. IF dir = 0 THEN INC(newX)
  130. ELSIF dir = 1 THEN DEC(newX)
  131. ELSIF dir = 2 THEN INC(newY)
  132. END;
  133. SetBlock(posX, posY, TRUE);
  134. IF ~HasCollision(block, newX, newY) THEN posX := newX; posY := newY; result := TRUE
  135. ELSE result := FALSE
  136. END;
  137. SetBlock(posX, posY, FALSE);
  138. AddDirty(posX * BoxSize - BoxSize, posY * BoxSize - BoxSize, posX * BoxSize + BlockSize * BoxSize + BoxSize,
  139. posY * BoxSize + BlockSize*BoxSize +BoxSize);
  140. RETURN result
  141. END Move;
  142. PROCEDURE KeyPressed(ucs : LONGINT; flags: SET; keysym: LONGINT);
  143. VAR ignore : BOOLEAN;
  144. rotBlock : Block;
  145. BEGIN {EXCLUSIVE}
  146. IF ~alive THEN RETURN END;
  147. IF Inputs.Release IN flags THEN RETURN END;
  148. IF (ucs = ORD("p")) OR (ucs = ORD("P")) THEN paused := ~paused END; (* IF paused THEN RETURN END;feature*)
  149. IF (keysym = 0FF50H) OR (keysym = 0FF51H) THEN ignore := Move(1); IF paused THEN INC(cheated) END
  150. ELSIF (keysym = 0FF55H)OR (keysym = 0FF53H) THEN ignore := Move(0); IF paused THEN INC(cheated) END
  151. ELSIF (keysym = 0FF52H) OR (keysym = 0FF09H) THEN
  152. SetBlock(posX, posY, TRUE);
  153. rotBlock := RotateBlock(block);
  154. IF ~HasCollision(rotBlock, posX, posY) THEN block := rotBlock END;
  155. SetBlock(posX, posY, FALSE);
  156. AddDirty(posX * BoxSize - BoxSize, posY * BoxSize - BoxSize, posX * BoxSize + BlockSize * BoxSize,
  157. posY * BoxSize + BlockSize * BoxSize);
  158. IF paused THEN INC(cheated) END
  159. ELSIF (keysym = 0FF54H) OR (keysym = 0FF0DH) OR (keysym = 20H) THEN
  160. dropped := TRUE; IF paused THEN INC(cheated) END
  161. END
  162. END KeyPressed;
  163. PROCEDURE NewBlock;
  164. VAR i, j: LONGINT; kind : LONGINT;
  165. color : CHAR;
  166. PROCEDURE Set(x, y: LONGINT);
  167. BEGIN block[x, y] := color
  168. END Set;
  169. BEGIN
  170. UpdateScore(FALSE);
  171. dropped := FALSE;
  172. posX := Width DIV 2 - 1; posY := 0;
  173. FOR i := 0 TO BlockSize - 1 DO FOR j := 0 TO BlockSize - 1 DO block [i, j] := 0X END END;
  174. kind := random.Integer() MOD NofBlocks;
  175. color := CHR(1 + kind);
  176. CASE kind OF
  177. 0 : Set(0, 2); Set(1, 2); Set(2, 2); Set(3, 2)
  178. |1 : Set(1, 3); Set(2, 3); Set(3, 3); Set(2, 2)
  179. |2 : Set(1, 1); Set(1, 2); Set(2, 2); Set(2, 3)
  180. |3 : Set(2, 1); Set(1, 2); Set(2, 2); Set(1, 3)
  181. |4 : Set(2, 1); Set(2, 2); Set(2, 3); Set(3, 3)
  182. |5 : Set(2, 1); Set(2, 2); Set(2, 3); Set(1, 3)
  183. |6 : Set(1, 1); Set(1, 2); Set(2, 1); Set(2, 2)
  184. END;
  185. INC(blocks);
  186. IF HasCollision(block, posX, posY) THEN alive := FALSE; END
  187. END NewBlock;
  188. PROCEDURE RemoveLine(y: LONGINT);
  189. VAR i, j: LONGINT;
  190. BEGIN
  191. FOR i := 0 TO Width - 1 DO
  192. FOR j := y TO 1 BY - 1 DO
  193. field[i, j] := field[i, j - 1];
  194. DrawBox(i, j, field[i, j])
  195. END;
  196. field[i, 0] := 0X;
  197. DrawBox(i, 0, 0X)
  198. END;
  199. AddDirty(0, 0, Width * BoxSize, y * BoxSize + BoxSize);
  200. INC(lines);
  201. timer.Sleep(200);
  202. IF delay > 10 THEN DEC(delay, delayDec) END;
  203. IF delayDec >= 4 THEN delayDec := delayDec * 2 DIV 3 END
  204. END RemoveLine;
  205. PROCEDURE ClearLines;
  206. VAR y, x, c: LONGINT;
  207. BEGIN
  208. y := Height - 1;
  209. WHILE y > 0 DO
  210. c := 0; FOR x := 0 TO Width - 1 DO IF field[x, y] # 0X THEN INC(c) END END;
  211. IF c = Width THEN RemoveLine(y) ELSE DEC(y) END
  212. END
  213. END ClearLines;
  214. PROCEDURE DropStep;
  215. VAR needNew: BOOLEAN;
  216. BEGIN {EXCLUSIVE}
  217. AWAIT(~paused);
  218. SetBlock(posX, posY, TRUE);
  219. IF ~HasDownCollision(posX, posY +1) THEN INC(posY); needNew := FALSE ELSE needNew := TRUE END;
  220. SetBlock(posX, posY, FALSE);
  221. AddDirty(posX * BoxSize - BoxSize, posY * BoxSize - BoxSize, posX * BoxSize + BlockSize * BoxSize,
  222. posY * BoxSize + BlockSize*BoxSize);
  223. IF needNew THEN
  224. ClearLines;
  225. NewBlock
  226. END
  227. END DropStep;
  228. PROCEDURE UpdateScore(eog: BOOLEAN);
  229. VAR pix : Raster.Pixel; str : ARRAY 16 OF CHAR; ypos : LONGINT;
  230. BEGIN
  231. Raster.SetRGB(pix, 255, 255, 255);
  232. Raster.Fill(img, 0, Height * BoxSize, Width * BoxSize, Height * BoxSize + ScoreHeight, pix, mode);
  233. Strings.IntToStr(lines*10+blocks, str);
  234. ypos := Height * BoxSize +13;
  235. canvas.DrawString(0, ypos, "Score:"); canvas.DrawString(100, ypos, str); INC(ypos, 13);
  236. Strings.IntToStr(GetGamesRunning(), str);
  237. canvas.DrawString(0, ypos, "Games active:"); canvas.DrawString(100, ypos, str); INC(ypos, 13);
  238. Strings.IntToStr(GetMaxConcurrent(), str);
  239. canvas.DrawString(0, ypos, "Max concurrent:"); canvas.DrawString(100, ypos, str); INC(ypos, 13);
  240. Strings.IntToStr(GetGamesTotal(), str);
  241. canvas.DrawString(0, ypos, "Served total:"); canvas.DrawString(100, ypos, str);INC(ypos, 13);
  242. Strings.IntToStr(GetHighscore(), str);
  243. canvas.DrawString(0, ypos, "High score:"); canvas.DrawString(100, ypos, str);INC(ypos, 13);
  244. canvas.DrawString(0, ypos, "Press p to toggle pause"); INC(ypos, 13);
  245. IF GetIsShuttingDown() THEN
  246. canvas.DrawString(0, ypos, "THE SERVER IS SHUTTING DOWN"); INC(ypos, 13)
  247. END;
  248. IF (cheated >= 5) & eog THEN
  249. canvas.DrawString(0, ypos, "Phuking cheater !"); INC(ypos, 13)
  250. END;
  251. AddDirty(0, Height * BoxSize, Width * BoxSize, Height * BoxSize + ScoreHeight);
  252. END UpdateScore;
  253. PROCEDURE AwaitRun;
  254. BEGIN {EXCLUSIVE}
  255. AWAIT(run)
  256. END AwaitRun;
  257. BEGIN {ACTIVE}
  258. AwaitRun;
  259. IP.AdrToStr(vncInfo.connection.fip, adrStr);
  260. KernelLog.Enter;
  261. Strings.DateToStr(Dates.Now(), timeStr); KernelLog.String(timeStr); KernelLog.String(" ");
  262. Strings.TimeToStr(Dates.Now(), timeStr); KernelLog.String(timeStr);
  263. KernelLog.String(" IP: "); KernelLog.String(adrStr);
  264. KernelLog.String(":"); KernelLog.Int(vncInfo.connection.fport, 5);
  265. KernelLog.String(" started");
  266. KernelLog.Exit;
  267. AddGame;
  268. alive := ~GetIsShuttingDown(); delay :=300; delayDec := 20;
  269. NewBlock;
  270. WHILE alive DO
  271. IF ~dropped THEN timer.Sleep(delay) END;
  272. DropStep
  273. END;
  274. KernelLog.Enter;
  275. Strings.DateToStr(Dates.Now(), timeStr); KernelLog.String(timeStr); KernelLog.String(" ");
  276. Strings.TimeToStr(Dates.Now(), timeStr); KernelLog.String(timeStr);
  277. KernelLog.String(" IP: "); KernelLog.String(adrStr);
  278. KernelLog.String(":"); KernelLog.Int(vncInfo.connection.fport, 5);
  279. KernelLog.String(" Score: "); KernelLog.Int(lines * 10 + blocks, 1);
  280. IF (cheated > 0) THEN KernelLog.String(" (cheated "); KernelLog.Int(cheated, 0); KernelLog.String(" times)") END;
  281. KernelLog.Exit;
  282. SubGame;
  283. IF (cheated < 5) THEN ReportScore(lines * 10 + blocks) END;
  284. UpdateScore(TRUE)
  285. END TT;
  286. PROCEDURE StartTT(vncInfo : VNCServer.VNCInfo);
  287. VAR t: TT;
  288. BEGIN
  289. NEW(t, vncInfo);
  290. vncInfo.img := t.img;
  291. vncInfo.kl := t.KeyPressed;
  292. t.Run
  293. END StartTT;
  294. PROCEDURE AddGame;
  295. BEGIN {EXCLUSIVE}
  296. INC(gamesTotal);
  297. INC(gamesRunning);
  298. maxConcurrent := MAX(gamesRunning, maxConcurrent)
  299. END AddGame;
  300. PROCEDURE ReportScore(score:LONGINT);
  301. BEGIN {EXCLUSIVE}
  302. highScore := MAX(score, highScore)
  303. END ReportScore;
  304. PROCEDURE GetGamesTotal():LONGINT;
  305. BEGIN {EXCLUSIVE}
  306. RETURN gamesTotal
  307. END GetGamesTotal;
  308. PROCEDURE GetMaxConcurrent():LONGINT;
  309. BEGIN {EXCLUSIVE}
  310. RETURN maxConcurrent
  311. END GetMaxConcurrent;
  312. PROCEDURE GetHighscore():LONGINT;
  313. BEGIN {EXCLUSIVE}
  314. RETURN highScore
  315. END GetHighscore;
  316. PROCEDURE GetGamesRunning():LONGINT;
  317. BEGIN {EXCLUSIVE}
  318. RETURN gamesRunning
  319. END GetGamesRunning;
  320. PROCEDURE GetIsShuttingDown():BOOLEAN;
  321. BEGIN {EXCLUSIVE}
  322. RETURN shuttingDown
  323. END GetIsShuttingDown;
  324. PROCEDURE SubGame;
  325. BEGIN {EXCLUSIVE}
  326. DEC(gamesRunning)
  327. END SubGame;
  328. (* Standard Procedures *)
  329. PROCEDURE Run*(context : Commands.Context);
  330. BEGIN
  331. ReadData;
  332. server := VNCServer.OpenService(5999, StartTT);
  333. context.out.String("VNC Tetris server started."); context.out.Ln;
  334. END Run;
  335. PROCEDURE StopNew*(context : Commands.Context);
  336. BEGIN {EXCLUSIVE}
  337. shuttingDown := TRUE;
  338. context.out.String("VNC Tetris server shut down."); context.out.Ln;
  339. END StopNew;
  340. PROCEDURE Uninstall*;
  341. VAR f: Files.File; w: Files.Writer;
  342. BEGIN
  343. IF server # NIL THEN
  344. f := Files.New(DataFile);
  345. IF f # NIL THEN
  346. Files.OpenWriter(w, f, 0);
  347. w.RawLInt(highScore);
  348. w.RawLInt(gamesTotal);
  349. w.RawLInt(maxConcurrent);
  350. w.Update();
  351. Files.Register(f)
  352. END;
  353. server.Close
  354. END;
  355. END Uninstall;
  356. PROCEDURE Cleanup;
  357. BEGIN
  358. Uninstall;
  359. END Cleanup;
  360. PROCEDURE ReadData;
  361. VAR f: Files.File; r: Files.Reader;
  362. BEGIN
  363. f := Files.Old(DataFile);
  364. IF f # NIL THEN
  365. Files.OpenReader(r, f, 0);
  366. r.RawLInt(highScore);
  367. r.RawLInt(gamesTotal);
  368. r.RawLInt(maxConcurrent)
  369. END
  370. END ReadData;
  371. BEGIN
  372. Raster.SetRGBA(colors[0], 0, 0, 0, 255);
  373. Raster.SetRGBA(colors[1], 255, 0, 0, 255);
  374. Raster.SetRGBA(colors[2], 0, 255, 0, 255);
  375. Raster.SetRGBA(colors[3], 0, 0, 255, 255);
  376. Raster.SetRGBA(colors[4], 200, 200, 0, 255);
  377. Raster.SetRGBA(colors[5], 255, 0, 255, 255);
  378. Raster.SetRGBA(colors[6], 0, 255, 255, 255);
  379. Raster.SetRGBA(colors[7], 256, 128, 100, 255);
  380. Modules.InstallTermHandler(Cleanup)
  381. END VNCTetrisServer.
  382. Aos.Call VNCTetrisServer.Run
  383. Aos.Call VNCTetrisServer.StopNew
  384. Aos.Call VNCTetrisServer.Uninstall
  385. System.Free VNCTetrisServer VNCServer~