Steve Losh avatar Steve Losh committed 8809191


Comments (0)

Files changed (6)


-Remove the distinction between items and creatures.  ALL THING ARE ENTITY.
-    (defprocotol Entity
-      (tick [this game])
-      (get-location [this game?])
-      (get-id [this]))
-    (def Entity
-      (with-meta Entity :default-fns
-        {:tick         (fn [this game] game)
-         :get-location (fn [this game] (:location this))
-         :get-id       (fn [this] (:id this))}))
-Individual things will implement the protocol:
-    (defrecord Pixie [id location])
-    (extend-entity Pixie
-      (tick [this game]
-         (do-stuff game)))
-    (extend Pixie Entity
-      (merge {:tick (fn [this game] game)
-              :get-location (fn [this game] (:location this))
-              :get-id (fn [this] (:id this))}
-             {:tick (fn [this game]
-                      (do-stuff game))}))
-    (defmacro extend-entity [cls & fns]
-      (let [fnmap (into {}
-                    (for [[fn-name & fn-tail] fns]
-                      [(keyword fn-name) fn-tail]))]
-        `(extend ~cls Entity
-          (merge default-entity-fns
-                 ~fnmap))))
-The Entity protocol should be very sparse.  Most functionality will come from
-other protocols that can be "added in" on a case-by-case basis.  Like mixins,
-but without the monkeypatching clusterfuck.
-Sample Entities
-A Fungus might look like:
-    (extend' Fungus Destructible ...)
-    (extend' Fungus Metabolizer ...)
-Funguses don't do much.  They do draw nutrition from the soil though, so their
-nutritional value should grow over time until they split.
-    (extend' Goblin Mobile ...)
-    (extend' Goblin Destructible ...)
-    (extend' Goblin Attacker ...)
-    (extend' Goblin AI ...)
-    (extend' Goblin Container ...)
-    (extend' Goblin Wearer ...)
-    (extend' Goblin Wielder ...)
-    (extend' Goblin Eater ...)
-    (extend' Goblin Metabolizer ...)
-Goblines are mobs that can walk around, be killed, kill things, have an
-inventory, wear armor and wield weapons, eat food, and burn their eaten food.
-    (extend' Pixie Mobile ...)
-    (extend' Pixie Destructible ...)
-    (extend' Pixie Attacker ...)
-    (extend' Pixie AI ...)
-    (extend' Pixie Item ...)
-    (extend' Pixie Applicable ...)
-    (extend' Pixie Edible ...)
-Here Pixies are entities that move around, can be destroyed (i.e. killed), can
-attack other entities, have an AI to decide actions (put this in tick?).  Sounds
-like a normal monster, but they can also function as an item if you pick them
-up.  They can then be applied or eaten.
-Ideas for Entity Protocols
-### Entity
-Base protocol.  All entities must implement this.
-Basically it's implementation-related stuff that's not gameplay-related.
-Exception: materials?
-### Mobile
-Can move autonomously.
-### Item
-Can be placed in a container.
-### Armor
-Can be worn as armor by wearers.
-### Weapon
-Can be used as a weapon by wielders.
-### Container
-Can hold things that implement Item.  Creatures can be Containers -- this
-effectively means they have an inventory.
-### Food
-Can be eaten by Eaters (maybe).
-### Quaffable
-Can be drunk by drinkers.
-### Eater
-Can eat Food (maybe).
-### Drinker
-Can drink Quaffables (maybe).
-### Metabolizer
-Has a notion of "energy" that either decreases over time (hunger) or increases
-over time (photosynthesis).
-### Destructible
-Can be destroyed by physical (or magical) trauma.  Usually handled through HP
-### Decaying
-Can transform to something else (or nothing) over a period of time.
-### Attacker
-Can physically attack other creatures.
-### Wielder
-Can use other entities as weapons if they implement Weapon.
-### Wearer
-Can use other entities as armor if they implement Armor.
-### Sentient
-Has an alignment.  Not sure about this one.


 (defn tick-all [world]
   (reduce tick-entity world (vals (:entities world))))
+(defn clear-messages [game]
+  (assoc-in game [:world :entities :player :messages] nil))
 (defn run-game [game screen]
   (loop [{:keys [input uis] :as game} game]
     (when (seq uis)
       (if (nil? input)
-        (let [game (update-in game [:world] tick-all)]
-          (draw-game game screen)
+        (let [game (update-in game [:world] tick-all)
+              _ (draw-game game screen)
+              game (clear-messages game)]
           (recur (get-input game screen)))
         (recur (process-input (dissoc game :input) input))))))


 (ns caves.entities.aspects.attacker
-  (:use [caves.entities.aspects.destructible :only [Destructible take-damage
+  (:use [caves.entities.aspects.receiver :only [send-message]]
+        [caves.entities.aspects.destructible :only [Destructible take-damage
         [caves.entities.core :only [defaspect]]))
 (defaspect Attacker
   (attack [this target world]
     {:pre [(satisfies? Destructible target)]}
-    (take-damage target (get-damage this target world) world))
+    (let [damage (get-damage this target world)]
+      (->> world
+        (take-damage target damage)
+        (send-message this "You strike the %s for %d damage!"
+                      [(:glyph target) damage])
+        (send-message target "The %s strikes you for %d damage!"
+                      [(:glyph target) damage]))))
   (attack-value [this world]
     (get this :attack 1)))


+(ns caves.entities.aspects.receiver
+  (:use [caves.entities.core :only [defaspect]]))
+(defaspect Receiver
+  (receive-message [this message world]
+    (update-in world [:entities (:id this) :messages] conj message)))
+(defn send-message [entity message args world]
+  (if (satisfies? Receiver entity)
+    (receive-message entity (apply format message args) world)
+    world))


 (ns caves.entities.player
   (:use [caves.entities.core :only [Entity add-aspect]]
+        [caves.entities.aspects.receiver :only [Receiver]]
         [ :only [Mobile move can-move?]]
         [caves.entities.aspects.digger :only [Digger dig can-dig?]]
         [caves.entities.aspects.attacker :only [Attacker attack]]
 (add-aspect Player Digger)
 (add-aspect Player Attacker)
 (add-aspect Player Destructible)
+(add-aspect Player Receiver)
 (defn make-player [location]
   (map->Player {:id :player


     (s/move-cursor screen x y)))
+(defn draw-messages [screen messages]
+  (when (seq messages)
+    (s/put-sheet screen 0 0 messages)))
 (defmethod draw-ui :play [ui game screen]
   (let [world (:world game)
         {:keys [tiles entities]} world
     (doseq [entity (vals entities)]
       (draw-entity screen origin entity))
     (draw-hud screen game)
+    (draw-messages screen (:messages player))
     (highlight-player screen origin player)))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.