aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game.scm82
-rw-r--r--src/macroknight/game.hy32
-rw-r--r--src/tilemap.scm193
3 files changed, 290 insertions, 17 deletions
diff --git a/src/game.scm b/src/game.scm
new file mode 100644
index 0000000..1e9da8b
--- /dev/null
+++ b/src/game.scm
@@ -0,0 +1,82 @@
+(import scheme
+ (chicken base)
+ (chicken format)
+ (chicken process-context)
+ (chicken condition)
+ (chicken pretty-print)
+ (srfi 1)
+ miscmacros
+ (prefix sdl2 "sdl2:")
+ (prefix sdl2-ttf "ttf:")
+ (prefix sdl2-image "img:")
+ tilemap)
+
+(define +color-depth+ 32)
+(define +screen-width+ 600)
+(define +screen-height+ 400)
+(define *fullscreen?* #f)
+(define +background-color+ (sdl2:make-color 0 0 0))
+(define +software-mode?+ (member "--software" (command-line-arguments)))
+(define +vsync?+ (member "--vsync" (command-line-arguments)))
+
+(sdl2:set-main-ready!)
+(sdl2:init! '(video joystick))
+(ttf:init!)
+(img:init! '(png))
+
+(on-exit sdl2:quit!)
+
+;; Install a custom exception handler that will call quit! and then
+;; call the original exception handler. This ensures that quit! will
+;; be called even if an unhandled exception reaches the top level.
+(current-exception-handler
+ (let ((original-handler (current-exception-handler)))
+ (lambda (exception)
+ (sdl2:quit!)
+ (original-handler exception))))
+
+(if (and +vsync?+ (not +software-mode?+)) ; vsync doesn't work with software rendering
+ (sdl2:set-hint! 'render-vsync "1"))
+(define *window* (sdl2:create-window! "MacroKnight"
+ 'centered 'centered
+ +screen-width+ +screen-height+
+ (if *fullscreen?* '(fullscreen) '())))
+(define *renderer* (sdl2:create-renderer! *window* -1
+ (if +software-mode?+ '(software) '(accelerated))))
+
+(define *font* (ttf:open-font "DejaVuSans.ttf" 12))
+(define *text-color* (sdl2:make-color 255 255 255))
+(pp (sdl2:num-joysticks))
+(define *joystick* (if (> (sdl2:num-joysticks) 0)
+ (sdl2:joystick-open! 0)
+ #f))
+(define *level* (load-tilemap "assets/level-0.tmx"))
+
+(define (draw-tile target tileset tile-id)
+ 123)
+
+(set! (sdl2:render-draw-color *renderer*) +background-color+)
+(sdl2:render-clear! *renderer*)
+
+(let/cc exit-main-loop!
+ (while #t
+ (set! (sdl2:render-draw-color *renderer*) +background-color+)
+ (sdl2:render-clear! *renderer*)
+ (sdl2:pump-events!)
+ (while (sdl2:has-events?)
+ (let ((event (sdl2:make-event)))
+ (sdl2:poll-event! event)
+ (pp event)
+ (when (and (sdl2:keyboard-event? event)
+ (eq? (sdl2:event-type event) 'key-down)
+ (eq? (sdl2:keyboard-event-sym event) 'escape))
+ (exit-main-loop!))))
+
+ (sdl2:render-present! *renderer*)
+
+ (sdl2:delay! 10)))
+
+(sdl2:joystick-close *joystick*)
+
+(format #t "Bye!\n")
+
diff --git a/src/macroknight/game.hy b/src/macroknight/game.hy
index 8675f81..125768a 100644
--- a/src/macroknight/game.hy
+++ b/src/macroknight/game.hy
@@ -39,8 +39,6 @@
(load_pygame "assets/level-2.tmx")
(load_pygame "assets/level-3.tmx")])
(setv level-id 0)
-(setv game-won False)
-(setv game-lost False)
(defn abs-to-tile-index [abs-id]
(int (floor (/ abs-id TILE_SIZE))))
@@ -86,7 +84,7 @@
TILE_SIZE
tile-x
tile-y)))))
-
+
(setv player-pos
(let [player-objects (lfor ent (get level.layers 1) :if (= ent.type "Player") ent)]
(if (any player-objects)
@@ -94,9 +92,10 @@
#((abs-to-tile-index player-object.x)
(abs-to-tile-index player-object.y)))
#(5 5))))
- (setv player (Player 1 [(get tileset.tiles 28)
- (get tileset.tiles 29)] TILE_SIZE #* player-pos))
+ (setv player (Player (len entities) [(get tileset.tiles 28)
+ (get tileset.tiles 29)] TILE_SIZE #* player-pos))
(.append entities player)
+
(setv macro-input-mode False)
(setv macro-wait-time 0)
(setv macro-commands [None None None])
@@ -202,8 +201,17 @@
(setv level-id (+ level-id 1))
(setv running False)
(when (>= level-id (len levels))
- (setv game-running False)
- (setv game-won True)))
+ (setv level-id 0)
+ (.fill screen "#000000")
+
+ (render-text screen
+ tileset
+ "YOU WIN"
+ 15
+ 14)
+
+ (pygame.display.flip)
+ (pygame.time.wait 1000)))
(except [PlayerKilled]
(setv running False)))
@@ -221,16 +229,6 @@
(.tick clock 60)))
-(when game-won
- (.fill screen "#000000")
-
- (render-text screen
- tileset
- "YOU WIN"
- 10
- 10)
- (pygame.display.flip)
- (pygame.time.wait 1000))
(pygame.quit)
diff --git a/src/tilemap.scm b/src/tilemap.scm
new file mode 100644
index 0000000..e80978e
--- /dev/null
+++ b/src/tilemap.scm
@@ -0,0 +1,193 @@
+(module tilemap
+(load-tilemap)
+(import scheme
+ (chicken io)
+ (chicken base)
+ (chicken string)
+ (chicken format)
+ (chicken process-context)
+ (chicken pathname)
+ (chicken pretty-print)
+ (srfi 1)
+ expat
+ defstruct
+ (prefix sdl2-image "img:"))
+
+(defstruct tileset
+ tilewidth
+ tileheight
+ spacing
+ tilecount
+ columns
+ image-source
+ image)
+
+(defstruct layer
+ name
+ width
+ height
+ map)
+
+(defstruct object
+ name
+ type
+ x
+ y
+ width
+ height
+ properties)
+
+(defstruct tilemap
+ width
+ height
+ tilewidth
+ tileheight
+ tileset-source
+ tileset
+ layers
+ objects)
+
+(define (maybe-do action)
+ (lambda (value)
+ (if (eq? value #f)
+ #f
+ (action value))))
+
+(define (attempt action)
+ (lambda (value)
+ (or (action value) value)))
+
+(define maybe-string->number (maybe-do (attempt string->number)))
+
+(define (string-alist->alist string-alist)
+ (map (lambda (pair) (cons (string->symbol (car pair))
+ (maybe-string->number (cdr pair))))
+ string-alist))
+
+(define (parse-tileset string-tileset)
+ (let ((parser (expat:make-parser))
+ (tags '())
+ (tileset (make-tileset 0 0 0 0 0 "")))
+ (expat:set-start-handler! parser
+ (lambda (tag attrs)
+ (let ((symbol-attrs (string-alist->alist attrs)))
+ (cond ((string=? tag "tileset")
+ (set! tileset (alist->tileset symbol-attrs)))
+ ((string=? tag "image")
+ (tileset-image-source-set! tileset (alist-ref 'source symbol-attrs)))))
+ (set! tags (cons tag tags))))
+ (expat:set-end-handler! parser (lambda (tag)
+ (set! tags (cdr tags))))
+ (expat:set-character-data-handler! parser (lambda (line) #f))
+ (expat:parse parser string-tileset)
+ tileset))
+
+(define (load-tileset file-name)
+ (call-with-input-file file-name
+ (lambda (port)
+ (let* ((tileset (parse-tileset (read-string #f port)))
+ (image-source (tileset-image-source tileset))
+ (base-path (pathname-directory file-name))
+ (img-to-load (if (absolute-pathname? image-source)
+ image-source
+ (pathname-replace-directory
+ image-source
+ (if (pathname-directory image-source)
+ (format "~a/~a" base-path (pathname-directory image-source))
+ base-path)))))
+ (tileset-image-set! tileset (img:load img-to-load))
+ tileset))))
+
+(define (parse-tilemap string-tilemap)
+ (let ((parser (expat:make-parser))
+ (tags '())
+ (tilemap (make-tilemap 0 0 0 0 '() '() '()))
+ (layer '()))
+ (expat:set-start-handler! parser
+ (lambda (tag attrs)
+ (let ((symbol-attrs (string-alist->alist attrs)))
+ (cond ((string=? tag "map")
+ (tilemap-width-set! tilemap (alist-ref 'width symbol-attrs))
+ (tilemap-height-set! tilemap (alist-ref 'height symbol-attrs))
+ (tilemap-tilewidth-set! tilemap (alist-ref 'tilewidth symbol-attrs))
+ (tilemap-tileheight-set! tilemap (alist-ref 'tileheight symbol-attrs)))
+ ((string=? tag "tileset")
+ (tilemap-tileset-source-set! tilemap (alist-ref 'source symbol-attrs)))
+ ((string=? tag "layer")
+ (set! layer (alist->layer attrs)))
+ ((string=? tag "object")
+ (tilemap-objects-set! tilemap (cons (alist->object symbol-attrs)
+ (tilemap-objects tilemap)))))
+ (set! tags (cons tag tags)))))
+ (expat:set-end-handler! parser (lambda (tag)
+ (when (string=? tag "layer")
+ (tilemap-layers-set! tilemap
+ (cons layer (tilemap-layers tilemap)))
+ (set! layer '()))
+ (set! tags (cdr tags))))
+ (expat:set-character-data-handler! parser (lambda (line)
+ (when (string=? (car tags) "data")
+ (let ((txt (string-chomp line)))
+ (when (not (string=? txt ""))
+ (layer-map-set! layer (append
+ (or (layer-map layer) '())
+ (list (map string->number
+ (string-split txt ","))))))))))
+ (expat:parse parser string-tilemap)
+ tilemap))
+
+(define (load-tilemap file-name)
+ (call-with-input-file file-name
+ (lambda (port)
+ (let* ((tilemap (parse-tilemap (read-string #f port)))
+ (base-path (pathname-directory file-name))
+ (tileset-source (tilemap-tileset-source tilemap)))
+ (tilemap-tileset-set! tilemap (load-tileset
+ (if (absolute-pathname? tileset-source)
+ tileset-source
+ (pathname-replace-directory
+ tileset-source
+ (if (pathname-directory tileset-source)
+ (format "~a/~a" base-path (pathname-directory tileset-source))
+ base-path))
+ )))
+ tilemap))))
+
+(when #f
+
+ (let ((txt "<?xml version='1.0' encoding='UTF-8'?>
+<tileset version='1.10' tiledversion='1.11.2' name='monochrome_transparent' tilewidth='16' tileheight='16' spacing='1' tilecount='1078' columns='49'>
+ <image source='monochrome-transparent.png' width='832' height='373'/>
+</tileset>
+"))
+ (tileset-image (parse-tileset txt)))
+
+ (let ((txt "<?xml version='1.0' encoding='UTF-8'?>
+<map version='1.10' tiledversion='1.11.0' orientation='orthogonal' renderorder='right-down' width='40' height='30' tilewidth='16' tileheight='16' infinite='0' nextlayerid='8' nextobjectid='5'>
+ <tileset firstgid='1' source='monochrome_transparent.tsx'/>
+ <layer id='3' name='ground' width='40' height='30'>
+ <data encoding='csv'>
+0,0,0,0,168,169,0,0,0,0,
+844,0,0,0,0,0,845,546,546,546,
+</data>
+ </layer>
+ <objectgroup id='7' name='entities'>
+ <object id='2' name='player' type='Player' gid='29' x='182' y='350.5' width='16' height='16'/>
+ <object id='3' name='hint' type='Text' x='98.5' y='432.5' width='197' height='78'>
+ <properties>
+ <property name='text' value='hit enter to start a macro'/>
+ </properties>
+ </object>
+ <object id='4' name='goal' type='Goal' x='560.935' y='288.641' width='16' height='16'/>
+ </objectgroup>
+</map>
+"))
+ (tilemap-tileset (parse-tilemap txt)))
+
+ (tileset-image (tilemap-tileset (load-tilemap "assets/level-0.tmx")))
+ )
+
+
+
+) ;; End tilemap module
+