1;; Defines the basic stuff for the haxima quest system 2 3;; Create a new quest. 4;; 5;; title - a string that will be shown in the quest log listing and at the top 6;; of the quest pane 7;; 8;; tag - an optional tag (preferably unique) that can be used to retrieve the quest. 9;; 10;; descr - a list of strings (ie paragraph) that will be shown in the quest pane 11;; 12;; assign - an optional symbol[1] for a proc that will run when the quest is assigned; 13;; of the form (assign quest target), where 'quest' is the thing being created right 14;; here and 'target' is the (scheme) object the quest is being assigned to. Iff 15;; 'assign' returns #t then the quest will be added to the target's list of 16;; quests. 17;; 18;; status - an optional symbol [1] for a proc that will be called by the ztats pane, of 19;; the form (status quest), when the quest details are shown in the quest log. 20;; It is called before the description is written, so it may alter that if required. 21;; The method should return a list of strings to be appended to the description, or nil 22;; Note that this should not be used to update the icon or inprog/done/failed status, as 23;; they are used in the preceeding panel. 24;; 25;; icon - symbol [1] for sprite to use for the quest UI 26;; 27;; payload - whatever you want for your particular quest (this is an optional 28;; number of parms) 29;; 30;; (* optional = use nil to ignore) 31;; 32;; Example: 33;; 34;; (qst-mk "Find 6 Foozles" 35;; '( 36;; "If you find 6 Foozles, Mr. Squeejie will give you an enchanted toothpick." 37;; "" 38;; "Seek them out in distant Foozleburg" 39;; ) 40;; 'find-foozle-assign 41;; 'find-foozle-status 42;; 's_quest_foozles 43;; 0 ; payload tracks num foozles found so far 44;; ) 45;; 46;; Notes: 47;; 48;; [1] The symbol of a proc named foo is 'foo. You must use a symbol because 49;; the name of the procedure must be saved as part of an object's gob. It would 50;; be nice if you could just pass in a lambda, but saving and reloading lambda 51;; closures is left as an exercise for the advanced reader. BTW, this rule 52;; applies within the payload lists as well. 53;; 54(define (qst-mk title tag descr assign status icon . payload) 55 (if (or (not (symbol? assign)) 56 (not (symbol? status))) 57 (error "qst-mk: 'assign' and 'status' must be the symbols for procedures (ie, not the procedures themselves)")) 58 (list 'quest title tag descr assign status 'inprogress icon payload)) 59 60(define (qst-title qst) (list-ref qst 1)) 61 62(define (qst-tag qst) (list-ref qst 2)) 63 64(define (qst-descr qst) (list-ref qst 3)) 65 66(define (qst-assign qst target) 67 (println "qst-assign") 68 (apply (eval (list-ref qst 4)) 69 (list qst target))) 70 71(define (qst-status qst) 72 (let ((statfn (list-ref qst 5))) 73 (if (not (null? statfn)) 74 (apply (eval statfn) (list qst)) 75 )) 76) 77 78(define (qst-done? qst) 79 ;;(println "qst-done? qst=" qst) 80 (list-ref qst 6)) 81 82(define (qst-done! qst result) 83 ;;(kern-log-msg "^c+gYou have completed the quest ^c+w" (qst-title qst) "^c-!^c-") 84 (if (not (equal? (list-ref qst 6) result)) 85 (begin 86 (list-set-ref! qst 6 result) 87 (qst-bump! qst) 88 ) 89 )) 90 91(define (qst-complete? qst) 92 (equal? (list-ref qst 6) 'complete)) 93 94(define (qst-complete! qst) 95 (qst-done! qst 'complete)) 96 97(define (qst-failed? qst) 98 (equal? (list-ref qst 6) 'failed)) 99 100(define (qst-failed! qst) 101 (qst-done! qst 'failed)) 102 103(define (qst-icon qst) (list-ref qst 7)) 104 105(define (qst-payload qst) (list-ref qst 8)) 106 107(define (quest-assign qst) 108 (println "quest-assign") 109 (let ((target (gob (kern-get-player)))) 110 (if (and (notnull? qst) 111 (notnull? target) 112 (qst-assign qst target)) 113 (begin 114 (quest-insert qst) 115 ;;(tbl-append! target 'quests qst) 116 ;;(println "quest-assign: " target) 117 ;;(kern-log-msg "^c+gYou have a new quest: " (qst-title qst) "^c-") 118 )))) 119 120(define (quest-assigned? qst) 121 (println "quest-assigned?") 122 (let* ((target (gob (kern-get-player))) 123 (qstlist (tbl-get target 'quests)) 124 ) 125 (if (or (null? qst) 126 (null? qstlist) 127 ) 128 #f 129 (in-list? qst qstlist) 130 ) 131 )) 132 133;; first item, if any, else nil 134(define (safe-car alist) 135 (cond ((null? alist) 136 nil) 137 ((pair? alist) 138 (car alist)) 139 (#t alist))) 140 141(define (quest-get tag) 142 (safe-car 143 (filter 144 (lambda (quest) (eq? (qst-tag quest) tag)) 145 (tbl-get (gob (kern-get-player)) 'quests) 146 ) 147 )) 148 149(define (quest-remove qst) 150 ;; (cons a nil) = a; (cons nil b) != b; 151 (define (quest-remove-helper qstlist) 152 (if (null? qstlist) nil 153 (let ((qhead (safe-car qstlist))) 154 (println "rem? " (eq? qhead qst) " " ) 155 (if (eq? qhead qst) 156 (cdr qstlist) 157 (cons 158 qhead 159 (quest-remove-helper (cdr qstlist)) 160 ) 161 ) 162 ) 163 )) 164 (let* ((target (gob (kern-get-player))) 165 (trimmed (quest-remove-helper (tbl-get target 'quests) qst)) 166 ) 167 (if (null? trimmed) 168 (tbl-rm! target 'quests) 169 (tbl-set! target 'quests trimmed) 170 ) 171 )) 172 173(define (qst-set-title! qst title) (list-set-ref! qst 1 title)) 174(define (qst-set-descr! qst descr) (list-set-ref! qst 3 descr)) 175(define (qst-set-icon! qst icon) (list-set-ref! qst 7 icon)) 176 177;; bump the quest to the top of its appropriate list 178(define (qst-bump! quest) 179 (define (qst-bump-base! qst) 180 (if (quest-assigned? qst) 181 (begin 182 (quest-remove qst) 183 (quest-insert qst) 184 ) 185 )) 186 ;; if we have a parent quest, bump that first 187 (let ((parent (quest-tbl-get quest 'qparent))) 188 (if (not (null? parent)) 189 (let ((pqst (quest-get parent))) 190 (if (not (null? pqst)) 191 (qst-bump! pqst) 192 )) 193 )) 194 (qst-bump-base! quest) 195 ;; if we have children, bump them 196 (let ((childlist (quest-tbl-get quest 'qchildren))) 197 (println childlist) 198 (map (lambda (entry) 199 (let ((cqst (quest-get entry))) 200 (if (not (null? cqst)) 201 (qst-bump-base! cqst) 202 ) 203 )) 204 childlist) 205 ) 206 ) 207 208(define (quest-insert qst) 209 (let* ((target (gob (kern-get-player))) 210 (targlist (tbl-get target 'quests)) 211 (inserttype (qst-done? qst)) 212 (parent (quest-tbl-get qst 'qparent)) 213 ) 214 (define (insert-here? testee) 215 (cond ((eq? inserttype 'inprogress) #t) 216 ((eq? inserttype (qst-done? testee)) #t) 217 ((eq? 'failed (qst-done? testee)) #t) 218 (#t #f)) 219 ) 220 (define (quest-insert-helper qstlist) 221 (if (null? qstlist) (list qst) 222 (let ((qhead (safe-car qstlist))) 223 (if (insert-here? qhead) 224 (cons qst qstlist) 225 (cons 226 qhead 227 (quest-insert-helper (cdr qstlist)) 228 ) 229 ) 230 ) 231 )) 232 (define (quest-insertchild-helper qstlist) 233 (if (null? qstlist) (list qst) 234 (let ((qhead (safe-car qstlist))) 235 (if (or (not (equal? parent (quest-tbl-get qhead 'qparent))) 236 (insert-here? qhead)) 237 (cons qst qstlist) 238 (cons 239 qhead 240 (quest-insertchild-helper (cdr qstlist)) 241 ) 242 ) 243 ) 244 )) 245 (define (quest-insert-findparent qstlist) 246 (if (null? qstlist) (nil) 247 (let ((qhead (safe-car qstlist))) 248 (if (equal? parent (qst-tag qhead)) 249 (cons 250 qhead 251 (quest-insertchild-helper (cdr qstlist)) 252 ) 253 (cons 254 qhead 255 (quest-insert-findparent (cdr qstlist)) 256 ) 257 ) 258 ) 259 )) 260 (cond ((null? targlist) (tbl-append! target 'quests qst)) 261 ((null? parent) (tbl-set! target 'quests (quest-insert-helper targlist))) 262 (#t (tbl-set! target 'quests (quest-insert-findparent targlist))) 263 ) 264 )) 265 266;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 267;; Some special handling for quests with tbl payloads 268 269(define (quest-tbl? quest) 270 (let ((qpayload (qst-payload quest))) 271 (cond ((not (pair? qpayload)) #f) 272 ((not (pair? (car qpayload))) #f) 273 (#t (is-tbl? (car qpayload))) 274 ) 275 )) 276 277(define (quest-tbl-get quest tag) 278 (let ((qpayload (qst-payload quest))) 279 (cond ((not (pair? qpayload)) nil) 280 ((not (pair? (car qpayload))) nil) 281 ((not (is-tbl? (car qpayload))) nil) 282 (#t (tbl-get (car qpayload) tag)) 283 ) 284 )) 285