(require hy) (require hyrule *) (import pygame pytmx.util_pygame [load_pygame] entities [Player LevelTile] tiles [TileSet draw-tile] utils [neg] text [render-text] systems [apply-gravity apply-collisions] math [floor]) (pygame.init) (setv TILE_SCALING 1) (setv TILE_SIZE (* TILE_SCALING 16)) (setv MACRO_STEP_WAIT 300) (setv MACRO_COOLDOWN 5000) (setv screen (pygame.display.set_mode #((* TILE_SCALING 640) (* TILE_SCALING 480)))) (setv clock (pygame.time.Clock)) (setv running True) (setv tileset (TileSet "assets/monochrome-transparent.png" TILE_SCALING TILE_SIZE TILE_SIZE 1)) (setv sprites-group []) (setv level (load_pygame "assets/level-0.tmx")) (defn abs-to-tile-index [abs-id] (int (floor (/ abs-id TILE_SIZE)))) (setv player-pos (let [player-objects (lfor ent (get level.layers 1) :if (= ent.type "Player") ent)] (if (any player-objects) (let [player-object (get player-objects 0)] #((abs-to-tile-index player-object.x) (abs-to-tile-index player-object.y))) #(5 5)))) (setv player (Player 1 (get tileset.tiles 28) TILE_SIZE #* player-pos)) (.append sprites-group player) (setv macro-input-mode False) (setv macro-wait-time 0) (setv macro-commands [None None None]) (for [tiledef (enumerate (.tiles (get level.layers 0)))] (.append sprites-group (LevelTile (get tiledef 0) TILE_SIZE TILE_SCALING #* (get tiledef 1)))) (setv ongoing_inputs []) (while running (for [event (pygame.event.get)] (case event.type pygame.QUIT (setv running False) pygame.KEYDOWN (if (= event.key pygame.K_ESCAPE) (setv running False) (if macro-input-mode (when (in event.key [pygame.K_a pygame.K_w pygame.K_a pygame.K_s pygame.K_d]) (setv (get macro-commands (.index macro-commands None)) event.key)) (if (and (= event.key pygame.K_SPACE) (= macro-wait-time 0)) (setv macro-input-mode True) (.append ongoing_inputs event.key)))) pygame.KEYUP (when (in event.key ongoing_inputs) (.remove ongoing_inputs event.key)))) (.fill screen "#000000") ;; Render text objects (for [item (get level.layers 1)] (when (= item.type "Text") (render-text screen tileset (.upper item.text) (abs-to-tile-index item.x) (abs-to-tile-index item.y)))) (if macro-input-mode ;; If the commands list is full (if (get macro-commands -1) ;; Process commands (do (let [#(command-id command) (get (lfor command (enumerate macro-commands) :if (get command 1) command) 0)] (case command pygame.K_a (.move player #((neg (* 2 TILE_SIZE)) 0)) pygame.K_s (.move player #(0 TILE_SIZE)) pygame.K_w (.move player #(0 (neg (/ player.MAX_JUMPING 2)))) pygame.K_d (.move player #((* 2 TILE_SIZE) 0))) (if (= command-id (- (len macro-commands) 1)) (do (setv macro-commands [None None None]) (setv macro-input-mode False) (setv macro-wait-time (+ (pygame.time.get_ticks) MACRO_COOLDOWN))) (setv (get macro-commands command-id) None))) (pygame.time.wait MACRO_STEP_WAIT)) ;; If there's still space in the commands list (for [#(num command) (enumerate macro-commands)] (let [x-pos (+ 4 num)] (case command pygame.K_w (draw-tile screen tileset 1057 x-pos 5) pygame.K_d (draw-tile screen tileset 1058 x-pos 5) pygame.K_s (draw-tile screen tileset 1059 x-pos 5) pygame.K_a (draw-tile screen tileset 1060 x-pos 5) None (draw-tile screen tileset 725 x-pos 5))))) ;; Not in macro mode (do (when (> macro-wait-time 0) (let [progress (round (* 3 (/ (- (pygame.time.get_ticks) macro-wait-time) MACRO_COOLDOWN)))] (for [indicator (range 3)] (draw-tile screen tileset 725 )))) (for [inp ongoing_inputs] (case inp pygame.K_a (.move player #((neg player.SPEED) 0)) pygame.K_s (.move player #(0 1)) pygame.K_w (.jump player) pygame.K_d (.move player #(player.SPEED 0)))) (when (any ongoing_inputs) (for [sprite sprites-group] (apply-collisions sprite sprites-group))) (.flush player) ;; Apply systems (for [sprite sprites-group] (apply-gravity sprite sprites-group) (apply-collisions sprite sprites-group)) (.flush player))) (for [sprite sprites-group] (.blit screen sprite.surf sprite.rect)) (pygame.display.flip) (when (or (= 0 macro-wait-time) (< (- (pygame.time.get_ticks) macro-wait-time) 0)) (setv macro-wait-time 0)) (.tick clock 60)) (pygame.quit)