diff options
Diffstat (limited to 'prefabs.scm')
| -rw-r--r-- | prefabs.scm | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/prefabs.scm b/prefabs.scm new file mode 100644 index 0000000..56bc60a --- /dev/null +++ b/prefabs.scm @@ -0,0 +1,91 @@ +(module downstroke-prefabs * + (import scheme + (chicken base) + (chicken keyword) + (chicken port) + defstruct + downstroke-entity + downstroke-ai) + + ;; Registry struct to hold prefab data + (defstruct prefab-registry + prefabs file engine-mixin-table user-hooks hook-table) + + ;; Return engine's built-in mixin table + (define (engine-mixins) + '((physics-body #:vx 0 #:vy 0 #:ay 0 #:gravity? #t #:solid? #t #:on-ground? #f) + (has-facing #:facing 1) + (animated #:anim-name idle #:anim-frame 0 #:anim-tick 0 #:tile-id 0) + (ai-body #:ai-facing 1 #:ai-machine #f #:chase-origin-x 0 #:disabled #f))) + + ;; Compose a prefab entry with mixin table + ;; Returns (name . merged-plist) + (define (compose-prefab entry mixin-table) + (let* ((name (car entry)) + (rest (cdr entry)) + (split (let loop ((lst rest) (mixins '())) + (if (or (null? lst) (keyword? (car lst))) + (cons (reverse mixins) lst) + (loop (cdr lst) (cons (car lst) mixins))))) + (mixin-names (car split)) + (inline-fields (cdr split)) + (mixin-plists + (map (lambda (mname) + (let ((m (assq mname mixin-table))) + (if m (cdr m) (error "Unknown mixin" mname)))) + mixin-names)) + ;; inline-fields prepended → first-match semantics give them highest priority + (merged (apply append inline-fields mixin-plists))) + (cons name merged))) + + ;; Engine-level hooks + (define *engine-hooks* + `((init-enemy-ai . ,(lambda (e) (entity-set e #:ai-machine (make-enemy-ai-machine)))))) + + ;; Lookup a hook symbol in the hook table + (define (lookup-hook hook-table hook-sym) + (let ((entry (assq hook-sym hook-table))) + (if entry + (cdr entry) + (error "Unknown prefab hook" hook-sym)))) + + (define (load-prefabs file engine-mixin-table user-hooks) + (let* ((data (with-input-from-file file read)) + (mixin-section (cdr (assq 'mixins data))) + (prefab-section (cdr (assq 'prefabs data))) + ;; user mixins first → user wins on assq lookup (overrides engine mixin by name) + (user-mixin-table (map (lambda (m) (cons (car m) (cdr m))) mixin-section)) + (merged-mixin-table (append user-mixin-table engine-mixin-table)) + ;; user-hooks first → user wins on assq lookup (overrides engine hooks by name) + (hook-table (append user-hooks *engine-hooks*)) + (prefab-table (map (lambda (entry) (compose-prefab entry merged-mixin-table)) + prefab-section))) + (make-prefab-registry + prefabs: prefab-table + file: file + engine-mixin-table: engine-mixin-table + user-hooks: user-hooks + hook-table: hook-table))) + + (define (reload-prefabs! registry) + (load-prefabs (prefab-registry-file registry) + (prefab-registry-engine-mixin-table registry) + (prefab-registry-user-hooks registry))) + + (define (instantiate-prefab registry type x y w h) + (if (not registry) + #f + (let ((entry (assq type (prefab-registry-prefabs registry)))) + (if (not entry) + #f + ;; instance fields prepended → highest priority + (let* ((base (append (list #:x x #:y y #:width w #:height h) + (cdr entry))) + (hook-val (entity-ref base #:on-instantiate #f)) + (handler + (cond + ((procedure? hook-val) hook-val) + ((symbol? hook-val) + (lookup-hook (prefab-registry-hook-table registry) hook-val)) + (else #f)))) + (if handler (handler base) base))))))) |
