diff --git a/COPYING b/COPYING index ba177ad..a665ff9 100644 --- a/COPYING +++ b/COPYING @@ -3,8 +3,11 @@ in XE2. XE2 is provided under the terms of the GNU General Public License, version 3. The game subdirectories include MEDIA-COPYING files which place the -included GRAPHICS AND SOUND files under a Creative Commons -License. See each game's MEDIA-COPYING file for details. +included GRAPHICS AND SOUND files under various licenses, including +Creative Commons licenses. See each game's MEDIA-COPYING file for +details. NOTE. SOME OF THE GAMES ARE LICENSED WITH ONE CC LICENSE, +SOME WITH ANOTHER. CHECK THE MEDIA-COPYING FILE IN EACH GAME'S +SUBDIRECTORY. The X11 color data is reproduced here in rgb.lisp under the MIT License; see rgb.lisp for details. diff --git a/forest/ascent-gateway.png b/forest/ascent-gateway.png new file mode 100644 index 0000000..7b48e4b Binary files /dev/null and b/forest/ascent-gateway.png differ diff --git a/forest/base.lisp b/forest/base.lisp index ebc86a5..8484f18 100644 --- a/forest/base.lisp +++ b/forest/base.lisp @@ -55,8 +55,27 @@ It has begun to snow." :water-grain 0.5 :water-density 80 :water-cutoff 0.3)) - (3 (list '=passage=)) - (4 (list '=monastery=)))) + (3 (list '=forest= + :level n + :description + "The trees thin here as you ascend toward the mountain pass." + :sequence-number (xe2:genseq) + :height *forest-height* + :width *forest-width* + :fireflies 20 + :graveyards 0 + :ruins 0 + :terrain-type :tundra + :snowing t + :firewood 25 + :archer-skeletons 8 + :tree-grain 0.9 + :tree-density 20 + :water-grain 0.5 + :water-density 0 + :water-cutoff 0.3)) + (4 (list '=passage=)) + (5 (list '=monastery=)))) ;;; Text overlay balloons diff --git a/forest/enemy.lisp b/forest/enemy.lisp index 90517a2..9659e65 100644 --- a/forest/enemy.lisp +++ b/forest/enemy.lisp @@ -98,7 +98,7 @@ (direction :initform nil) (speed :initform (make-stat :base 3)) (movement-cost :initform (make-stat :base 6)) - (hit-points :initform (make-stat :base 16 :min 0)) + (hit-points :initform (make-stat :base 12 :min 0)) (equipment-slots :initform '(:left-hand :right-hand)) (arrows :initform (make-stat :base 15 :min 0)) (max-items :initform (make-stat :base 3)) @@ -151,7 +151,7 @@ [expend-action-points self 10]) (multiple-value-bind (r c) (step-in-direction ) - [expend-action-points self 8] + [expend-action-points self 12] (when [obstacle-at-p world r c] [choose-new-direction self]) [move self ]))))) @@ -159,10 +159,83 @@ (define-method die archer-skeleton () (unless (setf t) - [drop self (clone =arrows= :count [stat-value self :arrows])] + (when (plusp [stat-value self :arrows]) + [drop self (clone =arrows= :count [stat-value self :arrows])]) [play-sample self "death-alien"] [delete-from-world self])) +;;; The horrifying Lich + +(defcell lichblade + (name :initform "lichblade") + (categories :initform '(:item :weapon :equipment)) + (tile :initform "dagger") + (attack-power :initform (make-stat :base 30)) + (attack-cost :initform (make-stat :base 30)) + (accuracy :initform (make-stat :base 90)) + (stepping :initform t) + (weight :initform 3000) + (equip-for :initform '(:left-hand :right-hand))) + +(define-prototype lich (:parent xe2:=cell=) + (name :initform "Lich") + (strength :initform (make-stat :base 29 :min 0 :max 40)) + (dexterity :initform (make-stat :base 15 :min 0 :max 30)) + (intelligence :initform (make-stat :base 19 :min 0 :max 30)) + (categories :initform '(:actor :target :obstacle :opaque :enemy :equipper)) + (equipment-slots :initform '(:left-hand :right-hand)) + (max-items :initform (make-stat :base 3)) + (stepping :initform t) + (speed :initform (make-stat :base 2)) + (movement-cost :initform (make-stat :base 8)) + (attacking-with :initform :left-hand) + (screamed :initform nil) + (max-weight :initform (make-stat :base 25)) + (hit-points :initform (make-stat :base 60 :min 0 :max 10)) + (tile :initform "lich") + (description :initform "The Lich is a rotting skeletal horror in red velvet robes.")) + +(define-method initialize lich () + [make-inventory self] + [make-equipment self]) + +(define-method loadout lich () + (let ((blade (clone =lichblade=))) + [equip self [add-item self blade]])) + +(define-method attack lich (target) + [damage [get-player *world*] 10] + [expend-action-points self 40] + [play-sample self "lichdie"] + [say self "The Lich screams 'DIE!' as it stabs at you."]) + +(define-method run lich () + (when (and (null ) + (< [distance-to-player self] 15)) + (setf t) + [play-sample self "lichscream"]) + (clon:with-field-values (row column) self + (let* ((world *world*) + (direction [direction-to-player *world* row column])) + (if [adjacent-to-player world row column] + [>>attack self direction] + (if [obstacle-in-direction-p world row column direction] + (let ((target [target-in-direction-p world row column direction])) + (if (and target (not [in-category target :enemy])) + [>>attack self direction] + (progn (setf (random-direction)) + [>>move self direction]))) + (progn (when (< 7 (random 10)) + (setf (random-direction))) + [>>move self direction])))))) + +(define-method die lich () + [say self "The lich dies!"] + [play-sample self "lichdeath"] + [parent>>die self]) + + + ;;; Wolves are the most difficult enemies. (defcell wolf diff --git a/forest/forest.fasl b/forest/forest.fasl index 7130083..5cb1c25 100644 Binary files a/forest/forest.fasl and b/forest/forest.fasl differ diff --git a/forest/forest.lisp b/forest/forest.lisp index 5d13a3d..c2f0b42 100644 --- a/forest/forest.lisp +++ b/forest/forest.lisp @@ -1,5 +1,43 @@ (in-package :forest) +;;; Icy tundra + +(defparameter *tundra-tiles* '("tundra-1" + "tundra-2" + "tundra-3" + "tundra-4" + "tundra-5" + "tundra-6" + "floor")) + +(defparameter *tundra-light-radius* 14) + + +(defcell tundra + (tile :initform "floor") + (description :initform "This frozen surface is treacherous.") + (categories :initform '(:actor :reflective))) + +(define-method blow tundra (dark) + (let ((snow [category-at-p *world* :snow])) + (when snow + [update-tile snow dark]) + (if (minusp ) + (progn (setf *snow-clock*) + (if (null snow) + (percent-of-time 3 + (setf snow (clone =snow=)) + [drop self snow]) + (percent-of-time 10 + [collect snow 1 dark]))) + (decf )))) + +(define-method run tundra () + (let* ((dist [distance-to-player self])) + (setf (if (< dist *tundra-light-radius*) + (nth (truncate (/ dist 2)) *tundra-tiles*) + "floor")))) + ;;; Water (defcell foam @@ -58,7 +96,7 @@ (defcell tree (tile :initform "tree-1") (description :initform "These trees are still green. Perhaps the land is coming back?") - (categories :initform '(:obstacle :opaque :nosnow))) + (categories :initform '(:obstacle :opaque :nosnow :exclusive))) ;;; The snow @@ -151,7 +189,7 @@ (defcell wall (tile :initform "wall") (description :initform "These crumbling walls are all that remain of some old town.") - (categories :initform '(:obstacle :opaque))) + (categories :initform '(:obstacle :opaque :exclusive))) (defcell debris (tile :initform "debris")) @@ -214,7 +252,6 @@ (setf clock (+ 5 (random 5))))))) [move self (random-direction)])) - ;;; Bodies of other adventurers (defcell body @@ -225,7 +262,7 @@ (define-method step body (stepper) (when [is-player stepper] [say self "You search the body."] - (unless (percent-of-time 30 + (unless (percent-of-time 40 (prog1 t [drop self (clone (car (one-of (list =herb= =arrows=))))])) [say self "Nothing was found."]) @@ -260,6 +297,11 @@ (dotimes (j ) [drop-cell self (clone =earth=) i j]))) +(define-method drop-tundra forest () + (dotimes (i ) + (dotimes (j ) + [drop-cell self (clone =tundra=) i j]))) + (define-method drop-trees forest (&optional &key (object =tree=) distance (row 0) (column 0) @@ -302,6 +344,16 @@ (define-method step river-gateway (stepper) [say self "The river meets the forest here. Press ENTER to continue on."]) +(define-prototype ascent-gateway (:parent =gateway=) + (tile :initform "ascent-gateway") + (name :initform "To the Ascent") + (description :initform "The trees thin here and the land becomes more icy.") + (sequence-number :initform (genseq)) + (address :initform (generate-level-address 3))) + +(define-method step ascent-gateway (stepper) + [say self "The climb begins here. Press ENTER to continue on."]) + (define-prototype passage-gateway (:parent =gateway=) (tile :initform "passage-gateway") (name :initform "Passage to the mountains") @@ -395,6 +447,7 @@ (ruins 15) (herbs 2) (firewood 14) + (terrain-type :earth) level snowing raining (tree-grain 0.3) (tree-density 30) @@ -409,7 +462,9 @@ (setf snowing raining) (setf level) [create-default-grid self] - [drop-earth self] + (ecase terrain-type + (:earth [drop-earth self]) + (:tundra [drop-tundra self])) [drop-cell self (clone =storm=) 0 0] (dotimes (i fireflies) (let ((firefly (clone =firefly=))) @@ -439,11 +494,17 @@ [drop-cell self (clone =archer-skeleton=) r c :exclusive t :probe t :loadout t])) (let* ((gateway (clone (ecase level (1 =river-gateway=) - (2 =passage-gateway=)))) + (2 =ascent-gateway=) + (3 =passage-gateway=)))) (row (+ (- height 10) (random 10))) ;; 20 FIXME (column (random 10))) [replace-cells-at *world* row column gateway] - [set-location gateway row column])) + [set-location gateway row column]) + ;; drop Lich if needed + (let ((lich (clone =lich=))) + (when (= level 3) + [drop-cell self lich (+ 60 (random 20)) (random width) :loadout t]))) + (define-method begin-ambient-loop forest () (play-sample "lutey") diff --git a/forest/forest.org b/forest/forest.org index 4115e7e..f92c4d9 100644 --- a/forest/forest.org +++ b/forest/forest.org @@ -1,17 +1,15 @@ +** TODO edible fruits to find +** TODO Catacombs ** TODO rose found in the forest -** TODO [#A] make wolves less annoying -** TODO more herbs on dead bodies' ** TODO [#A] fix 100% cpu usage *** WAITING talk to luke -** TODO rest and shelter ** TODO magic barrier shield (flickering sprites) ** TODO magic missile (sparkly trails.) ** TODO enemies search for dark spots -** TODO [#B] fix scrolling -** TODO [#C] Command-Q should quit on mac ? -** TODO [#A] don't place bodies in walls OR ITEMS -** TODO [#C] indicate edge of map with chevrons. piece together maps. -** TODO [#C] overworld map? (FUTURE) ** TODO [#B] fix in-game map scrolling off bottom of viewport ** TODO [#B] find in-game notes with same color scheme text as scroll ** TODO [#B] longer level approach to monastery, talk to a few npcs, follow a road and cross fences +** TODO [#C] fix scrolling +** TODO [#C] Command-Q should quit on mac ? +** TODO [#C] indicate edge of map with chevrons. piece together maps. +** TODO [#C] overworld map? (FUTURE) diff --git a/forest/forest.pak b/forest/forest.pak index 9654b9b..7e4a137 100644 --- a/forest/forest.pak +++ b/forest/forest.pak @@ -55,8 +55,11 @@ (:name "help-message" :type :formatted-text :file "README") (:name "snowflake" :type :image :file "snowflake.png") + (:name "lich" :type :image :file "lich.png") + (:name "lichblade" :type :image :file "lichblade.png") (:name "monastery" :type :image :file "monastery.png") (:name "monastery-gateway" :type :image :file "monastery-gateway.png") + (:name "ascent-gateway" :type :image :file "ascent-gateway.png") (:name "water-1" :type :image :file "water-1.png") (:name "water-2" :type :image :file "water-2.png") @@ -98,6 +101,9 @@ (:name "wall" :type :image :file "wall.png") (:name "dandelion" :type :image :file "dandelion.png") (:name "death" :type :sample :file "death.wav" :properties (:volume 40)) + (:name "lichdeath" :type :sample :file "lichdeath.wav" :properties (:volume 40)) + (:name "lichdie" :type :sample :file "lichdie.wav" :properties (:volume 40)) + (:name "lichscream" :type :sample :file "lichscream.wav" :properties (:volume 40)) (:name "death-alien" :type :sample :file "death-alien.wav" :properties (:volume 30)) (:name "knock" :type :sample :file "knock.wav" :properties (:volume 50)) (:name "monks" :type :sample :file "monks.wav" :properties (:volume 25)) diff --git a/forest/lich.png b/forest/lich.png new file mode 100644 index 0000000..3e2101f Binary files /dev/null and b/forest/lich.png differ diff --git a/forest/lichdeath.wav b/forest/lichdeath.wav new file mode 100644 index 0000000..03bd7d9 Binary files /dev/null and b/forest/lichdeath.wav differ diff --git a/forest/lichdie.wav b/forest/lichdie.wav new file mode 100644 index 0000000..623f2aa Binary files /dev/null and b/forest/lichdie.wav differ diff --git a/forest/lichscream.wav b/forest/lichscream.wav new file mode 100644 index 0000000..7870f71 Binary files /dev/null and b/forest/lichscream.wav differ diff --git a/forest/mountain.lisp b/forest/mountain.lisp index bffa9e4..b7a90c7 100644 --- a/forest/mountain.lisp +++ b/forest/mountain.lisp @@ -1,43 +1,5 @@ (in-package :forest) -;;; Icy tundra - -(defparameter *tundra-tiles* '("tundra-1" - "tundra-2" - "tundra-3" - "tundra-4" - "tundra-5" - "tundra-6" - "floor")) - -(defparameter *tundra-light-radius* 14) - - -(defcell tundra - (tile :initform "floor") - (description :initform "This frozen surface is treacherous.") - (categories :initform '(:actor :reflective))) - -(define-method blow tundra (dark) - (let ((snow [category-at-p *world* :snow])) - (when snow - [update-tile snow dark]) - (if (minusp ) - (progn (setf *snow-clock*) - (if (null snow) - (percent-of-time 3 - (setf snow (clone =snow=)) - [drop self snow]) - (percent-of-time 10 - [collect snow 1 dark]))) - (decf )))) - -(define-method run tundra () - (let* ((dist [distance-to-player self])) - (setf (if (< dist *tundra-light-radius*) - (nth (truncate (/ dist 2)) *tundra-tiles*) - "floor")))) - (defcell mountain (tile :initform "mountain") (description :initform "The walls of the passageway are slick with ice.")