Verified Commit d9ce4ffd authored by Andrew Kravchuk's avatar Andrew Kravchuk
Browse files

documentation improvements

parent 37fa1028
Diablo 2 is arguably one of the best action RPG created ever. This is humble attempt to recreate and, hopefully, deconstruct it using Common Lisp programming language and related techniques.
## Features
* Support for [Tiled]( map format.
* Support for [Aseprite]( sprite format.
* Entity-Component-System implementation.
* Powerful events subsystem (courtesy of [Shinmera's deeds library](
* 2D renderer with functional interface.
* Sprite batching subsystem.
* Naïve implementation of A* pathfinding algorithm.
* Powerful debugging facilities, including visual debugging.
* Loading assets from zip files.
* Simple yet powerful configuration subsystem.
* Logging subsystem.
## Installation
d2clone-kit requires [liballegro]( to function. To install liballegro, refer to your distribution's package manager; for instance, on Debian derivatives (including Ubuntu and Mint):
sudo apt-get install liballegro-acodec5.2 liballegro-audio5.2 liballegro-image5.2 \
liballegro-dialog5.2 liballegro-ttf5.2 liballegro-physfs5.2 liballegro-video5.2
Currently the following implementations are tested and supported by d2clone-kit:
Currently the following Common Lisp implementations are tested and supported by d2clone-kit:
* [SBCL](
* [CCL](
You can run it on x86_64 Linux, OS X, and Windows, where SBCL on Linux is the recommended platform.
You can run it on x86_64 Linux, OS X, and Windows, while SBCL on Linux is the recommended platform.
To install d2clone-kit, clone the repository to your Quicklisp's `local-projects` directory (assuming you have [Quicklisp]( installed):
$ git clone ~/quicklisp/local-projects/d2clone-kit
$ sbcl --quit --eval "(progn (ql:register-local-projects) (ql:quickload :d2clone-kit))"
## Glossary
* **map coordinates** - *world coordinates* of tile in staggered map grid.
......@@ -20,7 +43,7 @@ You can run it on x86_64 Linux, OS X, and Windows, where SBCL on Linux is the re
* **world coordinates** - floating point in-game world coordinates. One unit of length corresponds to one map tile width, typically 64 pixels.
## Legal
d2clone-kit is licensed under the GNU GPL license version 3. See LICENSE. TODO : link to file.
d2clone-kit is licensed under the GNU GPL license version 3. See [LICENSE](
Diablo® II - Copyright © 2000 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries.
This diff is collapsed.
......@@ -4,7 +4,10 @@
(defclass collision-system (system)
((name :initform 'collision)
(collision-map :initform nil))
(:documentation "Handles object collisions."))
(:documentation "Handles object collisions.
To make tile collide (e.g. be non-walkable by characters), set custom
boolean property *collides* to *true* in Tiled tileset."))
;; TODO : take into account characters?.. character movement event?..
......@@ -35,6 +35,7 @@ simple synchronous single-threaded event loop for now."))
(setf (macro-function 'defevent) (macro-function 'deeds:define-event)))
(defmacro issue (event-type &rest args)
"Shorthand macro to allow more convenient issuing of events."
`(deeds:do-issue ,event-type ,@args))
(defmacro defhandler (system event args &body options-and-body)
(in-package :d2clone-kit)
(cffi:define-foreign-library libphysfs
(:windows nil) ;; TODO : test Ш1ИДОШ5
(:windows nil)
(:unix (:or "" ""))
(t (:default "libphysfs")))
(cffi:use-foreign-library libphysfs)
......@@ -15,6 +15,8 @@
(declaim (inline make-growable-vector))
(defun make-growable-vector (&key (initial-element nil) (initial-allocated-size 1))
"Creates new growable vector with initial allocated size INITIAL-ALLOCATED-SIZE
(1 by default) and initial element INITIAL-ELEMENT (NIL by default)."
:vector (make-array initial-allocated-size :initial-element initial-element)
:size 0
......@@ -24,12 +26,14 @@
(inline growable-vector-ref)
(ftype (function (growable-vector array-index) t) growable-vector-ref))
(defun growable-vector-ref (growable-vector index)
(aref (%growable-vector-vector growable-vector) index))
(inline growable-vector-grow)
(ftype (function (growable-vector array-length)) growable-vector-grow))
(defun growable-vector-grow (growable-vector new-allocated-size)
"Adjusts GROWABLE-VECTOR to have allocated size of NEW-ALLOCATED-SIZE."
(let ((vector (%growable-vector-vector growable-vector)))
(when (> new-allocated-size (length vector))
(setf (%growable-vector-vector growable-vector)
......@@ -42,6 +46,7 @@
(inline (setf %growable-vector-ref))
(ftype (function (t growable-vector array-index) t) (setf %growable-vector-ref)))
(defun (setf %growable-vector-ref) (value growable-vector index)
"Access GROWABLE-VECTOR by INDEX with no bounds checking whatsoever."
(setf (%growable-vector-size growable-vector)
(max (%growable-vector-size growable-vector) (1+ index))
(aref (%growable-vector-vector growable-vector) index)
......@@ -51,6 +56,8 @@
(inline (setf growable-vector-ref))
(ftype (function (t growable-vector array-index) t) (setf growable-vector-ref)))
(defun (setf growable-vector-ref) (value growable-vector index)
"Access GROWABLE-VECTOR by INDEX, growing if necessary (when index is
greater than current allocated size)."
(let* ((vector (%growable-vector-vector growable-vector))
(allocated-size (length vector)))
(when (>= index allocated-size)
......@@ -70,12 +77,14 @@
(inline growable-vector-length)
(ftype (function (growable-vector) array-length) growable-vector-length))
(defun growable-vector-length (growable-vector)
"Returns GROWABLE-VECTOR length (i.e. current actual element count)."
(%growable-vector-size growable-vector))
(inline growable-vector-clear)
(ftype (function (growable-vector)) growable-vector-clear))
(defun growable-vector-clear (growable-vector)
"Removes all elements from GROWABLE-VECTOR."
(setf (%growable-vector-size growable-vector) 0))
......@@ -83,6 +92,7 @@
(ftype (function (growable-vector &key (:element-type symbol)) simple-array)
(defun growable-vector-freeze (growable-vector &key (element-type 't))
"Creates SIMPLE-ARRAY of ELEMENT-TYPE holding the same elements that GROWABLE-VECTOR holds."
(let* ((size (%growable-vector-size growable-vector))
(result (make-array size :element-type element-type)))
......@@ -2,7 +2,19 @@
(defclass map-system (system)
((name :initform 'map))
(:documentation "Handles map chunks in Tiled format."))
(:documentation "Handles map chunks in Tiled format.
The following format features are unsupported yet:
* maps made in Tiled < v0.15
* tile flipping
* external tileset files
* non-staggered maps
* stagger axis other than Y
* odd tile size
Also only integer map coordinates allowed for map chunks, otherwise the screen <-> map
conversion maths are badly fucked up."))
(defstruct map-tileset
(first-id 0 :type fixnum)
......@@ -210,7 +222,6 @@ See MAP->SCREEN"
(unless (and (intp x)
(intp y))
;; TODO : restart for rounding coordinates
;; Otherwise it will badly fuck up screen <-> map maths
(error "Only integer map coordinates allowed for map chunks"))))))
(defmethod system-draw ((system map-system) renderer)
......@@ -67,6 +67,15 @@
;; growable-vector.lisp
;; log.lisp
......@@ -92,10 +101,14 @@
;; priority-queue.lisp
;; renderer.lisp
......@@ -4,6 +4,7 @@
(:constructor %make-priority-queue)
(:copier nil)
(:predicate nil))
"A simple priority queue with DOUBLE-FLOAT priorities."
(array nil :type simple-vector)
(key nil :type (function (t) double-float) :read-only t))
......@@ -37,6 +38,8 @@ Note: keys are expected to be DOUBLE-FLOATs."
(inline priority-queue-find)
(ftype (function (priority-queue t)) priority-queue-find))
(defun priority-queue-find (queue element)
"Finds ELEMENT's position in QUEUE. Returns NIL if there's no such element.
O(log N) complexity."
(let* ((array (priority-queue-array queue))
(key-fn (priority-queue-key queue))
(position (binary-search key-fn (funcall key-fn element) array)))
......@@ -67,7 +70,10 @@ Note: keys are expected to be DOUBLE-FLOATs."
(inline priority-queue-push-many)
(ftype (function (priority-queue vector)) priority-queue-push-many))
(defun priority-queue-push-many (queue elements)
"Adds elements from vector ELEMENTS to priority queue QUEUE."
"Adds elements from vector ELEMENTS to priority queue QUEUE.
A bit more performance-friendly than calling PRIORITY-QUEUE-PUSH many times
(but complexity is still O(N log N))."
(let* ((array (priority-queue-array queue))
(old-length (length array)))
(setf (priority-queue-array queue)
......@@ -117,6 +123,7 @@ in appropriate order."
(inline priority-queue-pop)
(ftype (function (priority-queue)) priority-queue-pop))
(defun priority-queue-pop (queue)
"Removes and returns the first (priority-wise) element in QUEUE."
(multiple-value-bind (element new-array)
(simple-vector-pop (priority-queue-array queue))
(setf (priority-queue-array queue) new-array)
......@@ -126,6 +133,7 @@ in appropriate order."
(inline priority-queue-remove)
(ftype (function (priority-queue array-index)) priority-queue-remove))
(defun priority-queue-remove (queue index)
"Removes element from QUEUE denoted by INDEX."
(let ((array (priority-queue-array queue)))
(replace (priority-queue-array queue) array :start1 index :start2 (1+ index))
(setf (priority-queue-array queue)
......@@ -3,7 +3,14 @@
(defclass sprite-system (system)
((name :initform 'sprite))
(:documentation "Handles movable sprites in Aseprite format."))
(:documentation "Handles movable sprites in Aseprite format.
The following format features are unsupported yet:
* color modes other than RGBA
* group layers
* layer blend modes
* linked cels"))
(deftype angle ()
"Angle value in radians."
......@@ -101,6 +101,8 @@ See MAKE-PREFAB-COMPONENT"))
(defmacro defcomponent (system name &rest slots)
"Defines component structure with name NAME and slots SLOTS within system SYSTEM."
;; TODO : rewrite components storage using sparse array index based on growable vector to
;; remove unnecessary NIL checks and increase cache friendliness
(let* ((system-name (symbolicate system '-system))
(plural-name (string-upcase (plural-of name)))
(slot-names (mapcar #'car slots))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment