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.

465 linhas
15KB

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