Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

463 linhas
15KB

  1. ;;; Functions modeling a standard text adventure world.
  2. ;;; Location is modeled as containment, movement is modeled via passage nodes
  3. ;;; that hold properties and descriptions for a given exit.
  4. ;;; Global properties are held in the player object YOU, which also acts as
  5. ;;; the default avatar object.
  6. (module world (adventure create-object move-object add-alias set-hidden toggle-fixed set-enter-message set-destination get-container print-room-description)
  7. (import scheme)
  8. (import (chicken base))
  9. (import (chicken file))
  10. (import srfi-1)
  11. (import matchable)
  12. (import fmt)
  13. (import ansi-escape-sequences)
  14. (import util)
  15. (import database)
  16. (import io)
  17. ;; The canonical name of a given cardinal direction
  18. ;; and it's aliases.
  19. (define +cardinal-sets+
  20. '((north n)
  21. (northeast ne north-east)
  22. (east e)
  23. (southeast se south-east)
  24. (south s)
  25. (southwest sw south-west)
  26. (west w)
  27. (northwest nw north-west)
  28. (up u)
  29. (down d)))
  30. ;; The mirror direction for a given direction.
  31. (define +cardinal-opposites+
  32. '((north . south)
  33. (northeast . southwest)
  34. (east . west)
  35. (southeast . northwest)
  36. (south . north)
  37. (southwest . northeast)
  38. (west . east)
  39. (northwest . southeast)
  40. (up . down)
  41. (down . up)))
  42. ;; Main game loop exit condition.
  43. (define *exit-adventure* #f)
  44. (define-syntax get-set-define
  45. (er-macro-transformer
  46. (lambda (exp rename compare)
  47. (let ((flag (car exp)))
  48. (begin
  49. `(define (,(string->symbol (string-append (symbol->string flag) "-get")) object value)
  50. (database-get object ,flag value))
  51. `(define (,(string->symbol (string-append (symbol->string flag) "-set")) object value)
  52. (database-set object ,flag value)))))))
  53. (get-set-define test-value)
  54. ;; Set the name of an object.
  55. (define (set-name object name)
  56. (database-set object 'name name))
  57. ;; Set the description of an object.
  58. (define (set-description object description)
  59. (database-set object 'description description))
  60. ;; Get the name of an object.
  61. (define (get-name object)
  62. (database-get object 'name (symbol->string object)))
  63. ;; Get the description of an object.
  64. (define (get-description object)
  65. (database-get object 'description "You see the swirling void of creation."))
  66. (define (get-container object)
  67. (database-get object 'container #f))
  68. (define (get-contents object)
  69. (database-get object 'contents '()))
  70. (define (set-destination object destination)
  71. (database-set object 'destination destination))
  72. (define (get-destination object)
  73. (database-get object 'destination #f))
  74. (define (set-enter-message object msg)
  75. (database-set object 'enter-message msg))
  76. (define (get-enter-message object)
  77. (database-get object 'enter-message #f))
  78. (define (get-aliases object)
  79. (database-get object 'aliases '()))
  80. (define (set-aliases object alias-list)
  81. (database-set object 'aliases alias-list))
  82. (define (add-alias object alias)
  83. (let ((aliases (get-aliases object)))
  84. (if (not (member alias aliases))
  85. (set-aliases object (cons alias aliases)))))
  86. (define (remove-alias object alias)
  87. (let ((aliases (get-aliases object)))
  88. (if (member alias aliases)
  89. (set-aliases object (remove (curry eq? alias) aliases)))))
  90. (define (set-hidden object value)
  91. (database-set object 'hidden value))
  92. (define (get-hidden object)
  93. (database-get object 'hidden #f))
  94. (define (set-fixed object value)
  95. (database-set object 'fixed value))
  96. (define (get-fixed object value)
  97. (database-get object 'fixed #f))
  98. (define (get-put-message object)
  99. (database-get object 'put-message "You put the ~a into the ~a."))
  100. ;; Is development mode enabled?
  101. (define (devmode-enabled?)
  102. (database-get 'you 'devmode #f))
  103. (define (toggle-devmode)
  104. (toggle-flag 'you 'devmode))
  105. ;; Is an object fixed in place (e.g. cannot be picked up?)
  106. (define (fixed? object)
  107. (database-get object 'fixed #f))
  108. (define (toggle-fixed object)
  109. (toggle-flag object 'fixed))
  110. ;; Match a tag against a list of objects, checking for its tag and its aliases.
  111. (match-object tag objects)
  112. (let loop ((objects objects))
  113. (if (null? objects)
  114. #f
  115. (let ((taglist (cons (car objects) (get-aliases (car objects)))))
  116. (if (member tag taglist)
  117. (car objects)
  118. (loop (cdr objects)))))))
  119. (define (create-object tag name description)
  120. (set-name tag name)
  121. (set-description tag description))
  122. (define (move-object object container)
  123. (let ((prev-container (get-container object)))
  124. (database-set object 'container container)
  125. (let ((contents (get-contents container)))
  126. (if (not (member object contents))
  127. (begin
  128. (database-set container 'contents (cons object contents))
  129. (database-set prev-container 'contents (remove (curry eq? object) (get-contents prev-container))))))))
  130. ;; Determine the objects visible to a source object, zork-style
  131. (define (visible-objects source)
  132. (let ((result (get-container source)))
  133. (if (and result (object-exists? result))
  134. (cons (get-container source) (get-contents (get-container source)))
  135. (error "Tried to determine visible objects for object without a container."))))
  136. (define (print-room-description room)
  137. (newline)
  138. (display (set-text '(bold) (get-name room)))
  139. (if (devmode-enabled?) (display (set-text '(bold fg-green) (string-append " [" (symbol->string room) "]"))))
  140. (newline)
  141. (display " ")
  142. (fmt #t (dsp (wrap-lines (get-description room))))
  143. (newline)
  144. (display "You see: ")
  145. (map (lambda (n)
  146. (if (not (get-hidden n))
  147. (begin
  148. (display (get-name n))
  149. (display " ")
  150. (if (devmode-enabled?)
  151. (display (set-text '(bold fg-green) (string-append "[" (symbol->string n) "] "))))))) (remove (curry eq? 'you) (get-contents room)))
  152. (newline))
  153. (define (do-command-enter tag)
  154. (let ((object (match-object tag (visible-objects 'you))))
  155. (if (not object)
  156. (show "You cannot go that way.")
  157. (let ((destination (get-destination object)))
  158. (if (not destination)
  159. (show "You cannot enter that.")
  160. (begin
  161. (move-object 'you destination)
  162. (perhaps show (get-enter-message object))
  163. (print-room-description (get-container 'you))))))))
  164. (define (do-command-save)
  165. (let ((save-name (prompt-default "Enter save name: " "kekkonen.sav")))
  166. (if (or (not (file-exists? save-name)) (prompt-yn "That file already exists. Overwrite? "))
  167. (begin
  168. (show "Saving database, please wait...")
  169. (database-save save-name)
  170. (show "Done.")))))
  171. (define (do-command-load)
  172. (let ((save-name (prompt-default "Enter save file name to load: " "kekkonen.sav")))
  173. (if (not (file-exists? save-name))
  174. (show "That file does not exist.")
  175. (begin
  176. (show "Loading database, please wait...")
  177. (database-load save-name)
  178. (show "Done.")))))
  179. (define (do-command-look)
  180. (print-room-description (get-container 'you)))
  181. (define (do-command-examine tag)
  182. (let ((object (match-object tag (visible-objects 'you))))
  183. (if (not object)
  184. (show "You cannot see that here.")
  185. (show (get-description object)))))
  186. (define (do-command-inventory)
  187. (map (compose show get-name) (get-contents 'you)))
  188. (define (do-command-take tag)
  189. (if (not (symbol? tag))
  190. (show "I didn't quite understand that.")
  191. (let ((object (match-object tag (if (devmode-enabled?)
  192. (get-all-objects)
  193. (visible-objects 'you)))))
  194. (if (or (not object) (and (fixed? object) (not (devmode-enabled?))))
  195. (if object
  196. (show "That is fixed in place.")
  197. (show "You cannot see that here."))
  198. (begin
  199. (show (string-append "You get " (get-name object) "."))
  200. (move-object object 'you))))))
  201. (define (do-command-drop tag)
  202. (if (not (symbol? tag))
  203. (show "I didn't quite understand that.")
  204. (let ((object (match-object tag (get-contents 'you))))
  205. (if (not object)
  206. (show "You are not carrying that.")
  207. (begin
  208. (show (string-append "You drop " (get-name object) "."))
  209. (move-object object (get-container 'you)))))))
  210. (define (do-command-put tag destination-tag)
  211. (let ((object (match-object tag (get-contents 'you))))
  212. (if (not object)
  213. (show "You are not carrying that.")
  214. (let ((destination-object (match-object destination-tag (visible-objects 'you))))
  215. (if (not destination-object)
  216. (show "You cannot see that here.")
  217. (move-object object (get-destination destination-object)))))))
  218. (define (do-command-devmode)
  219. (toggle-devmode)
  220. (if (devmode-enabled?)
  221. (show "Development mode enabled.")
  222. (show "Development mode disabled.")))
  223. (define (do-command-create tag name description)
  224. (if (not (and (symbol? tag) (string? name) (string? description)))
  225. (show "I didn't quite understand that.")
  226. (if (object-exists? tag)
  227. (show "That object already exists.")
  228. (begin
  229. (create-object tag name description)
  230. (move-object tag (get-container 'you))))))
  231. (define (do-setter-command tag value type? setter)
  232. (if (not (and (symbol? tag) (type? value)))
  233. (show "I didn't quite understand that.")
  234. (let ((object (match-object tag (visible-objects 'you))))
  235. (if (not object)
  236. (show "You can't see that here.")
  237. (begin
  238. (setter object value)
  239. (show "You set a value."))))))
  240. (define (do-command-rename tag name)
  241. (do-setter-command tag name string? set-name))
  242. (define (do-command-describe tag description)
  243. (do-setter-command tag description string? set-description))
  244. (define (do-command-flag tag flag)
  245. (if (not (and (symbol? tag) (symbol? flag)))
  246. (show "I didn't quite understand that.")
  247. (let ((object (match-object tag (visible-objects 'you))))
  248. (if (not object)
  249. (show "You can't see that here.")
  250. (begin
  251. (case flag
  252. ((fixed) (set-fixed object #t))
  253. ((hidden) (set-hidden object #t))
  254. (else (show "Invalid flag name."))))))))
  255. (define (do-command-unflag tag flag)
  256. (if (not (and (symbol? tag) (symbol? flag)))
  257. (show "I didn't quite understand that.")
  258. (let ((object (match-object tag (visible-objects 'you))))
  259. (if (not object)
  260. (show "You can't see that here.")
  261. (begin
  262. (case flag
  263. ((fixed) (set-fixed object #f))
  264. ((hidden) (set-hidden object #f))
  265. (else (show "Invalid flag name."))))))))
  266. (define (do-command-alias tag alias)
  267. (if (not (and (symbol? tag) (symbol? alias)))
  268. (show "I didn't quite understand that.")
  269. (let ((object (match-object tag (visible-objects 'you))))
  270. (if (not object)
  271. (show "You can't see that here.")
  272. (begin
  273. (add-alias object alias)
  274. (show "You add an alias."))))))
  275. (define (do-command-unalias tag alias)
  276. (if (not (and (symbol? tag) (symbol? alias)))
  277. (show "I didn't quite understand that.")
  278. (let ((object (match-object tag (visible-objects 'you))))
  279. (if (not object)
  280. (show "You can't see that here.")
  281. (begin
  282. (remove-alias object alias)
  283. (show "You remove an alias."))))))
  284. (define (do-command-destroy tag)
  285. (if (not (symbol? tag))
  286. (show "I didn't quite understand that.")
  287. (database-remove tag)))
  288. (define (do-command-aliases tag)
  289. (if (not (symbol? tag))
  290. (show "I didn't quite understand that.")
  291. (let ((object (match-object tag (visible-objects 'you))))
  292. (if (not object)
  293. (show "You can't see that here.")
  294. (begin
  295. (newline)
  296. (map (lambda (x) (display x) (display " ")) (get-aliases object))
  297. (newline))))))
  298. (define (do-command-message tag message-tag message)
  299. (if (not (and (symbol? tag) (symbol? message-tag) (string? message)))
  300. (show "I didn't quite understand that.")
  301. (let ((object (match-object tag (visible-objects 'you))))
  302. (if (not object)
  303. (show "You can't see that here.")
  304. (case message-tag
  305. ((enter) (set-enter-message object message))
  306. (else (show "Invalid message name.")))))))
  307. (define (do-command-goto tag)
  308. (if (not (symbol? tag))
  309. (show "I didn't quite understand that.")
  310. (begin
  311. (move-object 'you tag)
  312. (print-room-description (get-container 'you)))))
  313. (define (get-cardinal-set direction)
  314. (find (curry member direction) +cardinal-sets+))
  315. (define (get-cardinal-aliases direction)
  316. (perhaps (curry remove (curry eq? direction)) (get-cardinal-set direction)))
  317. (define (cardinal-direction? direction)
  318. (list? (member direction (flatten +cardinal-sets+))))
  319. (define (get-inverse-direction direction)
  320. (perhaps cdr (assoc direction +cardinal-opposites+)))
  321. (define (get-canonical-cardinal-direction-name direction)
  322. (perhaps car (get-cardinal-set direction)))
  323. (define (do-command-dig direction destination)
  324. (if (not (and (symbol? direction) (symbol? destination)))
  325. (show "I didn't quite understand that.")
  326. (if (not (cardinal-direction? direction))
  327. (show "You must specify a compass rose direction or up and down.")
  328. (let ((canonical-direction (get-canonical-cardinal-direction-name direction)))
  329. (let ((exit-tag (compose-symbols canonical-direction (get-container 'you) destination)))
  330. (if (object-exists? exit-tag)
  331. (show "An exit like that already exists.")
  332. (begin
  333. (move-object exit-tag (get-container 'you))
  334. (set-hidden exit-tag #t)
  335. (set-destination exit-tag destination)
  336. (map (curry add-alias exit-tag) (get-cardinal-set direction))
  337. (show "You create a passage."))))))))
  338. (define (do-command-exit)
  339. (show "Goodbye, see you later...")
  340. (set! *exit-adventure* #t))
  341. (define (alias-transform input)
  342. (match input
  343. (('quit) '(exit))
  344. (('i) '(inventory))
  345. (('inv) '(inventory))
  346. (('look x) `(examine ,x))
  347. (('go x) `(enter ,x))
  348. (('get x) `(take ,x))
  349. ((x) (if (cardinal-direction? x)
  350. `(enter ,x)
  351. input))
  352. (_ input)))
  353. (define (dispatch-command input)
  354. (let ((success #t))
  355. (match input
  356. (('look) (do-command-look))
  357. (('save) (do-command-save))
  358. (('load) (do-command-load))
  359. (('devmode) (do-command-devmode))
  360. (('exit) (do-command-exit))
  361. (('enter x) (do-command-enter x))
  362. (('take x) (do-command-take x))
  363. (('drop x) (do-command-drop x))
  364. (('inventory) (do-command-inventory))
  365. (('examine x) (do-command-examine x))
  366. (('put x y) (do-command-put x y))
  367. (_ (if (devmode-enabled?)
  368. (match input
  369. (('create x y z) (do-command-create x y z))
  370. (('rename x y) (do-command-rename x y))
  371. (('describe x y) (do-command-describe x y))
  372. (('dig x y) (do-command-dig x y))
  373. (('flag x y) (do-command-flag x y))
  374. (('unflag x y) (do-command-unflag x y))
  375. (('alias x y) (do-command-alias x y))
  376. (('unalias x y) (do-command-unalias x y))
  377. (('destroy x) (do-command-destroy x))
  378. (('aliases x) (do-command-aliases x))
  379. (('message x y z) (do-command-message x y z))
  380. (('goto x) (do-command-goto x))
  381. (_ (set! success #f)))
  382. (set! success #f))))
  383. success))
  384. (define (adventure)
  385. (let ((success (dispatch-command (alias-transform (adventure-prompt)))))
  386. (if (not success)
  387. (begin
  388. (show "I didn't quite understand that.")
  389. (adventure))
  390. (if *exit-adventure*
  391. (show "Exiting..."); (display *database*)
  392. (adventure))))))