aboutsummaryrefslogtreecommitdiff
path: root/prefabs.scm
diff options
context:
space:
mode:
Diffstat (limited to 'prefabs.scm')
-rw-r--r--prefabs.scm91
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)))))))