PageRenderTime 72ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/src/examples/dragon.sc

https://bitbucket.org/bunny351/ezd
Scala | 614 lines | 538 code | 76 blank | 0 comment | 6 complexity | 437eee3ab295d7965de6aa29bb8e39ef MD5 | raw file
  1. ;;; DRAGON - a solitaire game played with mah-jongg tiles.
  2. ;* Copyright 1990 Digital Equipment Corporation
  3. ;* All Rights Reserved
  4. ;*
  5. ;* Permission to use, copy, and modify this software and its documentation is
  6. ;* hereby granted only under the following terms and conditions. Both the
  7. ;* above copyright notice and this permission notice must appear in all copies
  8. ;* of the software, derivative works or modified versions, and any portions
  9. ;* thereof, and both notices must appear in supporting documentation.
  10. ;*
  11. ;* Users of this software agree to the terms and conditions set forth herein,
  12. ;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
  13. ;* right and license under any changes, enhancements or extensions made to the
  14. ;* core functions of the software, including but not limited to those affording
  15. ;* compatibility with other hardware or software environments, but excluding
  16. ;* applications which incorporate this software. Users further agree to use
  17. ;* their best efforts to return to Digital any such changes, enhancements or
  18. ;* extensions that they make and inform Digital of noteworthy uses of this
  19. ;* software. Correspondence should be provided to Digital at:
  20. ;*
  21. ;* Director of Licensing
  22. ;* Western Research Laboratory
  23. ;* Digital Equipment Corporation
  24. ;* 250 University Avenue
  25. ;* Palo Alto, California 94301
  26. ;*
  27. ;* This software may be distributed (but not offered for sale or transferred
  28. ;* for compensation) to third parties, provided such third parties agree to
  29. ;* abide by the terms and conditions of this notice.
  30. ;*
  31. ;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  32. ;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  33. ;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
  34. ;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  35. ;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  36. ;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  37. ;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  38. ;* SOFTWARE.
  39. ;;; To interpret this program:
  40. ;;;
  41. ;;; csh >ezd -i
  42. ;;; Scheme->C -- 28sep90jfb -- Copyright 1989 Digital ...
  43. ;;; > (load "dragon.sc")
  44. ;;; MODULE form ignored
  45. ;;; (DEFINE-EXTERNAL EZD TOP-LEVEL)
  46. ;;; (DEFINE-EXTERNAL NOPIXMAP TOP-LEVEL)
  47. ;;; .
  48. ;;; .
  49. ;;; .
  50. ;;; SHOW-ALL-MOVES
  51. ;;; DRAGON-MAIN
  52. ;;; DRAGON
  53. ;;; HELP-TEXT
  54. ;;; "dragon.sc"
  55. ;;; > (dragon)
  56. ;;; > ^D
  57. ;;; csh >
  58. ;;;
  59. ;;; See the makefile to compile this program.
  60. (module dragon
  61. (with ezd)
  62. (heap 5)
  63. (main dragon-main))
  64. ;;; Externals
  65. (define-external ezd top-level)
  66. (define-external nopixmap top-level)
  67. (define-external *user-event-xevent* top-level)
  68. (define-external xevent-xbutton-time top-level)
  69. ;;; The following globals control how tiles are drawn.
  70. (define *TILE-ORIGIN-X* 10)
  71. (define *TILE-ORIGIN-Y* 10)
  72. (define *TILE-WIDTH* 30)
  73. (define *TILE-HEIGHT* 40)
  74. (define *TILE-SHADOW* 5)
  75. (define *TILE-ROWS* 8)
  76. (define *TILE-COLUMNS* 15)
  77. (define *TILE-ELEVATION* 5)
  78. (define *WINDOW-WIDTH* (+ (* (+ *tile-width* 1) *tile-columns*)
  79. (+ (* 2 *tile-origin-x*) *tile-shadow*)))
  80. (define *WINDOW-HEIGHT* (+ (* *tile-rows* (+ *tile-height* 1))
  81. (+ (* 2 *tile-origin-y*) *tile-shadow*)))
  82. ;;; The tiles are stacked in a 3-D "dragon" defined by *TILE-PLAN*. The
  83. ;;; tile plan is organized in levels from bottom to top. A non-zero value
  84. ;;; indicates a tile in that position. Tiles numbered 1 are in a normal
  85. ;;; position. Tiles numbered 2 are to be shifted 0.5 in the Y direction.
  86. ;;; Tiles numbered 3 are to be shifted -1.5 in the Y direction.
  87. ;;; Tiles numbered 4 are to be shifted in 0.5 in both the X and Y direction.
  88. (define *TILE-PLAN*
  89. '#( #(#(0 1 1 1 1 1 1 1 1 1 1 1 1 0 0)
  90. #(0 0 0 1 1 1 1 1 1 1 1 0 0 0 0)
  91. #(0 0 1 1 1 1 1 1 1 1 1 1 0 0 0)
  92. #(0 1 1 1 1 1 1 1 1 1 1 1 1 2 2)
  93. #(0 1 1 1 1 1 1 1 1 1 1 1 1 0 0)
  94. #(3 0 1 1 1 1 1 1 1 1 1 1 0 0 0)
  95. #(0 0 0 1 1 1 1 1 1 1 1 0 0 0 0)
  96. #(0 1 1 1 1 1 1 1 1 1 1 1 1 0 0))
  97. #(#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  98. #(0 0 0 0 1 1 1 1 1 1 0 0 0 0 0)
  99. #(0 0 0 0 1 1 1 1 1 1 0 0 0 0 0)
  100. #(0 0 0 0 1 1 1 1 1 1 0 0 0 0 0)
  101. #(0 0 0 0 1 1 1 1 1 1 0 0 0 0 0)
  102. #(0 0 0 0 1 1 1 1 1 1 0 0 0 0 0)
  103. #(0 0 0 0 1 1 1 1 1 1 0 0 0 0 0)
  104. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
  105. #(#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  106. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  107. #(0 0 0 0 0 1 1 1 1 0 0 0 0 0 0)
  108. #(0 0 0 0 0 1 1 1 1 0 0 0 0 0 0)
  109. #(0 0 0 0 0 1 1 1 1 0 0 0 0 0 0)
  110. #(0 0 0 0 0 1 1 1 1 0 0 0 0 0 0)
  111. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  112. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
  113. #(#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  114. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  115. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  116. #(0 0 0 0 0 0 1 1 0 0 0 0 0 0 0)
  117. #(0 0 0 0 0 0 1 1 0 0 0 0 0 0 0)
  118. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  119. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  120. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
  121. #(#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  122. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  123. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  124. #(0 0 0 0 0 0 4 0 0 0 0 0 0 0 0)
  125. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  126. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  127. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
  128. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
  129. ))
  130. ;;; There are four tiles of each type. The types are encoded in the form of
  131. ;;; a list of lists of color and text symbol.
  132. (define *TILE-TYPES*
  133. '((red "") (white "") (green "") ;;; Dragons
  134. (tan "N") (tan "S") (tan "E") (tan "W") ;;; Winds
  135. (magenta "") ;;; Flowers
  136. (goldenrod "") ;;; Seasons
  137. (yellow "1") (yellow "2") (yellow "3") ;;; Bams
  138. (yellow "4") (yellow "5") (yellow "6")
  139. (yellow "7") (yellow "8") (yellow "9")
  140. (plum "1") (plum "2") (plum "3") ;;; Dots
  141. (plum "4") (plum "5") (plum "6")
  142. (plum "7") (plum "8") (plum "9")
  143. (cyan "1") (cyan "2") (cyan "3") ;;; Craks
  144. (cyan "4") (cyan "5") (cyan "6")
  145. (cyan "7") (cyan "8") (cyan "9")))
  146. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  147. ;;; Procedures to draw tiles and handle events ;;;
  148. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  149. ;;; Each tile is represented by an instance of the following object. The
  150. ;;; arguments are:
  151. ;;;
  152. ;;; POSITION logical position in the dragon.
  153. ;;; X X coordinate for drawing the tile.
  154. ;;; Y Y coordinate for drawing the tile.
  155. ;;; COLOR color of the tile face.
  156. ;;; TEXT text written on the tile.
  157. (define (MAKE-TILE position x y color text)
  158. (let ((name (string->symbol (format "TILE-~s-~s" x y)))
  159. (visible #f)
  160. (type (list color text)))
  161. (define (BUTTON1DOWN)
  162. (if (tile-playable? position)
  163. (if *selected-tile*
  164. (if (eq? self *selected-tile*)
  165. (begin (set! *selected-tile* #f)
  166. (draw #f))
  167. (if (equal? type (*selected-tile* 'type))
  168. (begin (set! *deleted-tiles*
  169. (cons self
  170. (cons *selected-tile*
  171. *deleted-tiles*)))
  172. (clear)
  173. (*selected-tile* 'clear)
  174. (set! *selected-tile* #f)
  175. (if (null? *visible-tiles*)
  176. (for-each
  177. (lambda (tile)
  178. (ezd '(draw-now))
  179. (tile 'draw))
  180. *deleted-tiles*)))))
  181. (begin (set! *selected-tile* self)
  182. (draw #t)))))
  183. (define (BUTTON2DOWN)
  184. (let ((tiles '()))
  185. (define (LOWLIGHT)
  186. (for-each
  187. (lambda (tile)
  188. (or (eq? tile *selected-tile*)
  189. (tile 'lowlight)))
  190. tiles)
  191. (ezd `(when ,name button2up #f)
  192. `(when ,name exit #f)))
  193. (for-each
  194. (lambda (tile)
  195. (if (and (not (eq? tile self))
  196. (equal? (tile 'type) type))
  197. (let* ((p (tile 'position))
  198. (a (tile-above p)))
  199. (when (or (not a)
  200. (not (a 'visible))
  201. (eq? (caddr p)
  202. (- *tile-elevation*
  203. 2)))
  204. (set! tiles (cons tile tiles))
  205. (tile 'highlight)))))
  206. *visible-tiles*)
  207. (ezd `(when ,name button2up ,lowlight)
  208. `(when ,name exit ,lowlight))))
  209. (define (DRAW highlight)
  210. (if (not visible)
  211. (set! *visible-tiles* (cons self *visible-tiles*)))
  212. (set! visible #t)
  213. (draw-tile name x y *tile-width* *tile-height* *tile-shadow*
  214. color text highlight)
  215. (ezd `(when ,name button1down ,button1down)
  216. `(when ,name button2down ,button2down)))
  217. (define (CLEAR)
  218. (if visible
  219. (set! *visible-tiles* (remq! self *visible-tiles*)))
  220. (set! visible #f)
  221. (ezd '(set-drawing dragon)
  222. `(object ,name)))
  223. (define (SELF x)
  224. (case x
  225. ((highlight) (draw #t))
  226. ((lowlight) (draw #f))
  227. ((draw) (draw #f))
  228. ((clear) (clear))
  229. ((visible) visible)
  230. ((type) type)
  231. ((position) position)))
  232. (draw #f)
  233. self))
  234. ;;; When tiles are deleted from the dragon, they are placed on the following
  235. ;;; list.
  236. (define *DELETED-TILES* '())
  237. ;;; All tiles that are visible are on the following list.
  238. (define *VISIBLE-TILES* '())
  239. ;;; Event handling for tiles is done by the following procedure.
  240. ;;; Tiles are drawn by the following procedure.
  241. ;;;
  242. ;;; XY A-------D
  243. ;;; /| |
  244. ;;; SA | |
  245. ;;; | | |
  246. ;;; | | |
  247. ;;; | B-------C
  248. ;;; |/ /
  249. ;;; SB------SC
  250. (define (DRAW-TILE name x y w h shadow color text highlight)
  251. (let ((sa-x x)
  252. (sa-y (+ y shadow))
  253. (sb-x x)
  254. (sb-y (+ y shadow h))
  255. (sc-x (+ x w))
  256. (sc-y (+ y shadow h))
  257. (a-x (+ x shadow))
  258. (a-y y)
  259. (b-x (+ x shadow))
  260. (b-y (+ y h))
  261. (c-x (+ x shadow w))
  262. (c-y (+ y h))
  263. (d-x (+ x shadow w))
  264. (d-y y))
  265. (ezd `(set-drawing dragon)
  266. `(object ,name
  267. (fill-rectangle ,a-x ,a-y ,w ,h ,color)
  268. (fill-polygon ,sa-x ,sa-y ,sb-x ,sb-y ,sc-x ,sc-y
  269. ,c-x ,c-y ,b-x ,b-y ,a-x ,a-y wheat)
  270. (line ,sa-x ,sa-y ,a-x ,a-y)
  271. (line ,sb-x ,sb-y ,b-x ,b-y)
  272. (line ,sc-x ,sc-y ,c-x ,c-y 2)
  273. (line ,sa-x ,sa-y ,sb-x ,sb-y)
  274. (line ,sb-x ,sb-y ,sc-x ,sc-y 2)
  275. (rectangle ,a-x ,a-y ,w ,h)
  276. ,@(if highlight
  277. `((rectangle ,(+ a-x 2) ,(+ a-y 2)
  278. ,(- w 4) ,(- h 4) 3))
  279. '())
  280. (text ,(+ a-x 4) ,(+ a-y 4) ,(- w 8) ,(- h 8)
  281. right up ,text "8x13")))))
  282. ;;; In order to play the game, the program must have an understanding of the
  283. ;;; dragon's geometry. The data stuctures and query procedures for this
  284. ;;; information are maintained by the following procedures.
  285. (define *TILE-GEOMETRY* #f)
  286. (define *SELECTED-TILE* #f)
  287. (define (INIT-GEOMETRY)
  288. (set! *selected-tile* #f)
  289. (set! *tile-geometry*
  290. (let loop ((v *tile-plan*))
  291. (if (vector? v)
  292. (let ((vv (make-vector (vector-length v) #f)))
  293. (do ((i (- (vector-length v) 1) (- i 1)))
  294. ((= i -1) vv)
  295. (vector-set! vv i (loop (vector-ref v i)))))
  296. #f))))
  297. ;;; Return the tile to the left of a tile position.
  298. (define (TILE-LEFT position)
  299. (let ((x (- (car position) 1))
  300. (y (cadr position))
  301. (z (caddr position)))
  302. (if (= x -1)
  303. #f
  304. (vector-ref (vector-ref (vector-ref *tile-geometry* z) y) x))))
  305. ;;; Return the tile to the right of a tile position.
  306. (define (TILE-RIGHT position)
  307. (let ((x (+ (car position) 1))
  308. (y (cadr position))
  309. (z (caddr position)))
  310. (if (= x *tile-columns*)
  311. #f
  312. (vector-ref (vector-ref (vector-ref *tile-geometry* z) y) x))))
  313. ;;; Return the tile above a tile position.
  314. (define (TILE-ABOVE position)
  315. (let ((x (car position))
  316. (y (cadr position))
  317. (z (+ 1 (caddr position))))
  318. (if (= z *tile-elevation*)
  319. #f
  320. (vector-ref (vector-ref (vector-ref *tile-geometry* z) y) x))))
  321. ;;; Boolean to determine that a tile is playable.
  322. (define (TILE-PLAYABLE? position)
  323. (let ((left (tile-left position))
  324. (right (tile-right position))
  325. (above (tile-above position)))
  326. (if (or (and above (above 'visible))
  327. (and left right (left 'visible) (right 'visible)))
  328. #f
  329. #t)))
  330. ;;; Set an entry in *TILE-GEOMETRY*.
  331. (define (TILE-GEOMETRY! x y z v)
  332. (vector-set! (vector-ref (vector-ref *tile-geometry* z) y) x v))
  333. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  334. ;;; Procedures to draw the dragon ;;;
  335. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  336. ;;; The tiles are shuffled by calling the following procedure with a random
  337. ;;; integer. It returns a list of tiles.
  338. (define RAND0 0)
  339. (define (SHUFFLE-TILES)
  340. (let ((input (list->vector (append *tile-types* *tile-types* *tile-types*
  341. *tile-types*)))
  342. (output '())
  343. (m 144000)
  344. (a 3021)
  345. (c 713))
  346. (define (SELECT-ONE)
  347. (let ((x (modulo (+ (* a rand0) c) m)))
  348. (set! rand0 x)
  349. (let loop ((x (quotient rand0 1000)))
  350. (if (vector-ref input x)
  351. (let ((tile (vector-ref input x)))
  352. (vector-set! input x #f)
  353. tile)
  354. (loop (modulo (+ x 1) 144))))))
  355. (set! rand0 (inexact->exact (modulo (abs rand0) m)))
  356. (do ((i 0 (+ i 1)))
  357. ((= i (vector-length input)) output)
  358. (set! output (cons (select-one) output)))))
  359. ;;; The tiles are drawn by the following procedure.
  360. (define (DRAW-TILES origin-x origin-y w h s)
  361. (init-geometry)
  362. (do ((tiles (shuffle-tiles))
  363. (z 0 (+ z 1)))
  364. ((= z *tile-elevation*))
  365. (do ((y 0 (+ y 1)))
  366. ((= y *tile-rows*))
  367. (do ((x (- *tile-columns* 1) (- x 1)))
  368. ((= x -1))
  369. (let* ((type (vector-ref (vector-ref (vector-ref *tile-plan* z)
  370. y) x))
  371. (color-text (if (not (zero? type))
  372. (let ((x (car tiles)))
  373. (set! tiles (cdr tiles))
  374. x)
  375. #f)))
  376. (case type
  377. ((1) (let ((tile (make-tile (list x y z)
  378. (+ origin-x (* z s)
  379. (* x (+ w 1)))
  380. (+ origin-y (- (* z s))
  381. (* y (+ h 1)))
  382. (car color-text)
  383. (cadr color-text))))
  384. (tile-geometry! x y z tile)))
  385. ((2) (let ((tile (make-tile (list x y z)
  386. (+ origin-x (* z s)
  387. (* x (+ w 1)))
  388. (+ origin-y (- (* z s))
  389. (/ h 2)
  390. (* y (+ h 1)))
  391. (car color-text)
  392. (cadr color-text))))
  393. (tile-geometry! x y z tile)
  394. (tile-geometry! x (+ y 1) z tile)))
  395. ((3) (let ((tile (make-tile (list x y z)
  396. (+ origin-x (* z s)
  397. (* x (+ w 1)))
  398. (+ origin-y (- (* z s)) (- h)
  399. (- (/ h 2)) (* y (+ h 1)))
  400. (car color-text)
  401. (cadr color-text))))
  402. (tile-geometry! x (- y 2) z tile)
  403. (tile-geometry! x (- y 1) z tile)))
  404. ((4) (let ((tile (make-tile (list x y z)
  405. (+ origin-x (* z s) (/ w 2)
  406. (* x (+ w 1)))
  407. (+ origin-y (- (* z s))
  408. (/ h 2)
  409. (* y (+ h 1)))
  410. (car color-text)
  411. (cadr color-text))))
  412. (tile-geometry! x y z tile)
  413. (tile-geometry! x (+ y 1) z tile)
  414. (tile-geometry! (+ x 1) y z tile)
  415. (tile-geometry! (+ x 1) (+ y 1) z
  416. tile)))))))))
  417. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  418. ;;; Procedures to start the game ;;;
  419. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  420. ;;; Start a new game.
  421. (define (NEW-GAME)
  422. (ezd '(save-cursor dragon)
  423. '(set-cursor dragon xc_watch)
  424. '(set-drawing dragon)
  425. '(clear)
  426. `(object background (fill-rectangle 0 0 ,*window-width*
  427. ,*window-height* clear))
  428. `(object start (text 0 0 ,*window-width* ,*window-height*
  429. center center
  430. "...drawing tiles..." "9x15"))
  431. '(draw-now))
  432. (set! *deleted-tiles* '())
  433. (set! *visible-tiles* '())
  434. (draw-tiles
  435. *tile-origin-x* *tile-origin-y* *tile-width* *tile-height*
  436. *tile-shadow*)
  437. (ezd '(object start)
  438. '(when background button1down (dragon-menu))
  439. '(when background button2down (show-all-moves))
  440. '(restore-cursor dragon)))
  441. ;;; Undo the previous move.
  442. (define (UNDO)
  443. (when *deleted-tiles*
  444. (when *selected-tile*
  445. (*selected-tile* 'lowlight)
  446. (set! *selected-tile* #f))
  447. ((car *deleted-tiles*) 'draw)
  448. ((cadr *deleted-tiles*) 'draw)
  449. (set! *deleted-tiles* (cddr *deleted-tiles*))))
  450. ;;; Show all moves until the button comes up.
  451. (define (SHOW-ALL-MOVES)
  452. (let ((tiles '())
  453. (high-tiles '()))
  454. (define (LOWLIGHT)
  455. (ezd '(save-cursor dragon)
  456. '(set-cursor dragon xc_watch))
  457. (for-each (lambda (tile) (tile 'lowlight)) high-tiles)
  458. (if *selected-tile* (*selected-tile* 'highlight))
  459. (ezd '(set-drawing dragon)
  460. '(when background button2up #f)
  461. '(when background exit #f)
  462. '(restore-cursor dragon)))
  463. (define (ANOTHER-TILE? tile)
  464. (let ((type (tile 'type)))
  465. (let loop ((tiles tiles))
  466. (if (pair? tiles)
  467. (let ((x (car tiles)))
  468. (if (and (equal? (x 'type) type)
  469. (not (eq? x tile)))
  470. #t
  471. (loop (cdr tiles))))
  472. #f))))
  473. (ezd '(save-cursor dragon)
  474. '(set-cursor dragon xc_watch))
  475. (if *selected-tile* (*selected-tile* 'lowlight))
  476. (for-each
  477. (lambda (tile)
  478. (if (tile-playable? (tile 'position))
  479. (set! tiles (cons tile tiles))))
  480. *visible-tiles*)
  481. (for-each
  482. (lambda (tile)
  483. (when (another-tile? tile)
  484. (tile 'highlight)
  485. (set! high-tiles (cons tile high-tiles))))
  486. tiles)
  487. (ezd '(set-drawing dragon)
  488. `(when background button2up ,lowlight)
  489. `(when background exit ,lowlight)
  490. '(restore-cursor dragon))))
  491. ;;; Main.
  492. (define (DRAGON-MAIN clargs)
  493. (if (member "-nopixmap" clargs) (set! nopixmap #t))
  494. (dragon))
  495. (define (DRAGON)
  496. (define (START-UP)
  497. (set! rand0 (xevent-xbutton-time *user-event-xevent*))
  498. (new-game))
  499. (ezd '(quit)
  500. `(window dragon ,*window-width* ,*window-height* fixed-size)
  501. '(set-drawing dragon)
  502. '(overlay dragon dragon)
  503. `(object start
  504. (fill-rectangle 0 0 ,*window-width* ,*window-height* clear)
  505. (text 0 0 ,*window-width* 60
  506. center center "DRAGON" "vxms-37")
  507. ,@(help-text))
  508. `(when start button1down ,start-up)
  509. '(define-popup dragon-menu
  510. "UNDO" (undo) "NEW GAME" (new-game) "QUIT" (ezd '(quit)) "8x13")
  511. '(pause)))
  512. (define (HELP-TEXT)
  513. (let loop ((x 10)
  514. (y 60)
  515. (text '(
  516. "The \"dragon\" is a stack of 144 stylized mah-jongg tiles."
  517. "The object of the game is to remove all tiles from the"
  518. "stack, a matching pair at a time. The only tiles that"
  519. "can be removed are those at the left or right ends of a"
  520. "row. Use the mouse buttons as follows to play the game:"
  521. ""
  522. "Click button 1 to select and highlight the first tile of a"
  523. "pair to remove. Click button 1 on an identical tile to"
  524. "remove them. The highlight can be removed from the initial"
  525. "tile by clicking button 1 on it."
  526. ""
  527. "Press button 1 on the background to pop up an options menu."
  528. ""
  529. "Hold down button 2 on a tile to highlight all identical"
  530. "tiles that are visible. Hold down button 2 on the"
  531. "background to show all playable tiles."
  532. ""
  533. " CLICK BUTTON 1 TO START GAME"
  534. )))
  535. (if (pair? text)
  536. (cons `(text ,x ,y ,(car text) "8x13")
  537. (loop x (+ y 16) (cdr text)))
  538. '())))