inventory.lisp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. ;;;; Copyright © 2023, Jaidyn Ann <jadedctrl@posteo.at>
  2. ;;;;
  3. ;;;; This program is free software: you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU General Public License as
  5. ;;;; published by the Free Software Foundation, either version 3 of
  6. ;;;; the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This program is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;;;; GNU General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU General Public License
  14. ;;;; along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. ;;;; FLORA-SEARCH-AURORA.INVENTORY 🎒
  16. ;;;; The menu for inventory selection/management.
  17. (in-package :flora-search-aurora.inventory)
  18. ;;; ———————————————————————————————————
  19. ;;; Misc. Utils
  20. ;;; ———————————————————————————————————
  21. (defun subseq-head (length sequence)
  22. "Get a subsequence of SEQUENCE containing its first LENGTH elements. If LENGTH
  23. exceeds the size of SEQUENCE, the returned subsequence is equivalent to SEQUENCE."
  24. (subseq sequence 0 (…:at-most (length sequence) length)))
  25. ;;; ———————————————————————————————————
  26. ;;; Menu-creation! How fun!
  27. ;;; ———————————————————————————————————
  28. (defun items->menu-plist (item-plists &key (row-width 72))
  29. "Convert a list of items’ plists (that one might get from OVERWORLD’s map
  30. :ITEMS) into a pretty and presentable menu-grid of items, for use with
  31. 📋:MENU-STATE(-*)."
  32. (let* ((label-width 7)
  33. (border-width 2)
  34. ;; Weird bounding, whoops! I’m so clumsy, it’s endearing instead of just annoying! … Right? =w=”
  35. (column (- 0 label-width border-width))
  36. (row 0))
  37. (mapcar (lambda (item)
  38. (incf column (+ label-width border-width))
  39. (when (>= column row-width)
  40. (incf row)
  41. (setf column 0))
  42. (append (list :en (subseq-head label-width (or (getf (cdr item) :inv-name-en)
  43. (getf (cdr item) :name-en)
  44. (getf (cdr item) :id)))
  45. :eo (subseq-head label-width (or (getf (cdr item) :inv-name-eo)
  46. (getf (cdr item) :name-eo)))
  47. :selected (and (eq row 0) (eq column 0))
  48. :selection (if (and (eq row 0) (eq column 0)) 100 0)
  49. :submenu 't
  50. :row row)
  51. (cdr item)))
  52. item-plists)))
  53. ;;; ———————————————————————————————————
  54. ;;; Inventory loop logic
  55. ;;; ———————————————————————————————————
  56. (defun submenu (item)
  57. "Create a ITEM’s submenu, from its plist."
  58. (nconc (when (getf item :use)
  59. (list
  60. (list :en "Use it!"
  61. :eo "Uzi ĝin!"
  62. :selected 't :selection 100
  63. :use 't)))
  64. (list
  65. (list :en "Lose it!"
  66. :eo "Ne!"
  67. :use nil))))
  68. (defun inventory-state-update (map inventory-menu submenu)
  69. "The input-taking/logic-handling component of the inventory state-function.
  70. Part of INVENTORY-STATE."
  71. (let ((menu-return (📋:menu-state-update (if submenu submenu inventory-menu)))
  72. (selected-item (📋:selected-menu-item inventory-menu)))
  73. (cond
  74. ;; Display the pop-up menu when an item is selected.
  75. ((and (listp menu-return) (getf menu-return :submenu))
  76. (list :parameters (list :map map :inventory inventory-menu
  77. :submenu (submenu selected-item))))
  78. ;; User decided to use the item, let’s go!
  79. ((and (listp menu-return) (getf menu-return :use) (getf selected-item :use))
  80. (funcall (…:string->symbol (getf selected-item :use)) map selected-item))
  81. ;; User decided not to use the item.
  82. ((and (listp menu-return) (member :use menu-return))
  83. (list :parameters (list :map map :inventory inventory-menu)))
  84. ;; Return the menu itself, if non-nil.
  85. (menu-return
  86. 't)
  87. ;; If menu-return was non-nil, the user left the menu. Let’s leave inventory!
  88. ('t
  89. (list :drop 1 :parameters (list :map map))))))
  90. ;;; ———————————————————————————————————
  91. ;;; Inventory loop drawing
  92. ;;; ———————————————————————————————————
  93. (defun render-selected-item (matrix items)
  94. "Draw the title, avatar, and description of the currently-selected item to
  95. the bottom of the screen."
  96. (let* ((item (📋:selected-menu-item items))
  97. (name (list :en (or (getf item :name-en) (getf item :inv-name-en) (getf item :id))
  98. :eo (or (getf item :name-eo) (getf item :inv-name-eo))))
  99. (desc (list :en (getf item :desc-en)
  100. :eo (getf item :desc-eo))))
  101. (✎:render-string-verbatim matrix (str:concat ":" (…:getf-lang name) ": "
  102. (getf item :avatar))
  103. '(:x 1 :y 17))
  104. (✎:render-string matrix (…:getf-lang desc)
  105. '(:x 1 :y 18) :width 70)))
  106. (defun inventory-state-draw (matrix items submenu)
  107. "The drawing component of the inventory state-function.
  108. Part of INVENTORY-STATE."
  109. (📋:menu-state-draw matrix items)
  110. (render-selected-item matrix items)
  111. (when submenu
  112. (📋:menu-state-draw matrix submenu)))
  113. ;;; ———————————————————————————————————
  114. ;;; Inventory loop
  115. ;;; ———————————————————————————————————
  116. (defun inventory-state (matrix &key map inventory (submenu nil))
  117. "A state-function for use with STATE-LOOP."
  118. (sleep .02)
  119. (inventory-state-draw matrix inventory submenu)
  120. (inventory-state-update map inventory submenu))
  121. (defun make-inventory-function (map)
  122. "Return a state-function for inventory-listing, for use with STATE-LOOP."
  123. (lambda (matrix &key (map map) (submenu nil) (inventory (items->menu-plist (gethash :items map))))
  124. (apply #'🎒:inventory-state
  125. (list matrix :map map :inventory inventory :submenu submenu))))