;;; Copyright (C) 2025 Gene Pasquet ;;; ;;; This program is free software: you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License as published by ;;; the Free Software Foundation, either version 3 of the License, or ;;; (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . (require hyrule [case]) (import pygame.sprite [Sprite] pygame [Surface] pygame utils [neg merge-moves Direction] enum [Enum]) (defclass PlayerKilled [Exception]) (defclass Entity [Sprite] ;;; Game entity (setv _fixed False) (setv _type "none") (defn __init__ [self id tile tile-size x y] (.__init__ (super)) (setv self.id id) (setv self.tile-size tile-size) (setv self._surf (Surface #(tile-size tile-size))) (.blit self._surf tile #(0 0)) (setv self._rect (.get_rect self._surf :left (* x tile-size) :top (* y tile-size)))) (defn [property] fixed [self] self._fixed) (defn [property] rect [self] self._rect) (defn [property] surf [self] self._surf) (defn [property] type [self] self._type) (defn [property] pos [self] #((/ self.rect.x self.tile-size) (/ self.rect.y self.tile-size)))) (defclass LevelTile [Entity] (setv _fixed True) (setv _type "level") (defn __init__ [self id tile tile-size x y scaling] (let [tile-width (* (.get_width tile) scaling) tile-height (* (.get_height tile) scaling) tile_ (if (!= scaling 1) (pygame.transform.scale tile #(tile-width tile-height)) tile)] (.__init__ (super) id tile_ tile-size x y)))) (defclass Goal [Entity] (setv _type "goal") (setv _fixed True)) (defclass Player [Entity] (setv _type "player") (setv SPEED 3) (setv JUMP_IMPULSE 10) (setv MAX_JUMPING 100) (defn __init__ [self id tiles tile-size x y] (.__init__ (super) id (get tiles 0) tile-size x y) (setv self.tiles tiles) (setv self.jumping False) (setv self.jump-move 0) (setv self.moves []) (setv self._disp_surf (.copy self._surf)) (setv self.facing Direction.RIGHT) (setv self.attacking False) (setv self.animate-end 0)) (defn move [self move] (.append self.moves move) (.move_ip self._rect (get move 0) (get move 1)) (when (!= (get move 0) 0) (setv self.facing (.x-from-move Direction move)))) (defn [property] total-move [self] (merge-moves self.moves)) (defn attack [self] (setv self.attacking True)) (defn jump [self] (setv self.jumping True) (when (< self.jump-move self.MAX_JUMPING) (setv self.jump-move (+ self.jump-move self.JUMP_IMPULSE)) (.move self #(0 (neg self.JUMP_IMPULSE))))) (defn ground [self] (setv self.jump-move 0)) (defn animate [self ticks] ;; Attack animation (when (and self.attacking (= self.animate-end 0)) (setv self.animate-end (+ ticks 200)) (.blit self._surf (get self.tiles 1) #(0 0))) (when (and self.attacking (> ticks self.animate-end)) (setv self.animate-end 0) (setv self.attacking False) (.blit self._surf (get self.tiles 0) #(0 0))) ;; Facing direction (setv self._disp_surf (case self.facing Direction.LEFT (pygame.transform.flip self._surf True False) Direction.RIGHT (.copy self._surf))) (.flush self)) (defn flush [self] (setv self.moves [])) (defn [property] surf [self] self._disp_surf)) (defclass Enemy [Entity] (setv _type "enemy") (defn __init__ [self id tiles tile-size x y] (.__init__ (super) id (get tiles 0) tile-size x y) (setv self.tiles tiles) (setv self.facing Direction.RIGHT) (setv self.attacking False) (setv self.animate-end 0) (.flush self)) (defn move [self move] (.append self.moves move) (.move_ip self._rect (get move 0) (get move 1)) (when (!= (get move 0) 0) (setv self.facing (.x-from-move Direction move)))) (defn attack [self] (setv self.attacking True)) (defn flush [self] (setv self.moves [])) (defn ground [self]) (defn animate [self ticks] ;; Attack animation (when (and self.attacking (= self.animate-end 0)) (setv self.animate-end (+ ticks 200)) (.blit self._surf (get self.tiles 1) #(0 0))) (when (and self.attacking (> ticks self.animate-end)) (setv self.animate-end 0) (setv self.attacking False) (raise PlayerKilled) (.blit self._surf (get self.tiles 0) #(0 0))) (setv self._disp_surf (case self.facing Direction.LEFT (pygame.transform.flip self._surf True False) Direction.RIGHT (.copy self._surf))) (.flush self)) (defn [property] total-move [self] (merge-moves self.moves)) (defn [property] surf [self] self._disp_surf))