From 8f1d26a0c6065189cf04e95a7ac34c2baedcf2f4 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Wed, 13 Sep 2023 11:04:44 -0500 Subject: [PATCH] Early battle system --- src/minibaldur/core.clj | 30 +++++++++++++++++++++++------- src/minibaldur/ecs.clj | 2 +- src/minibaldur/engine.clj | 29 +++++++++++++++++++++-------- test/minibaldur/ecs_test.clj | 6 +++--- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/minibaldur/core.clj b/src/minibaldur/core.clj index 1920387..0a58a7d 100644 --- a/src/minibaldur/core.clj +++ b/src/minibaldur/core.clj @@ -3,20 +3,36 @@ (:require [minibaldur.ecs :refer :all] [minibaldur.engine :refer :all])) -(defcomponent goblin-ai :void) +(defcomponent name) +(defcomponent position) +(defcomponent health) +(defcomponent attack) (defentity (name "Goblin") (position {:x 0 :y 0 :z 0}) (health 10) - (attack "1d4 + 2") - (goblin-ai)) + (attack "1d4 + 2")) (defentity - (:name "Adventurer") - (:position {:x 0 :y 0 :z 0}) - (:health 20) - (:attack "1d6 + 3")) + (name "Adventurer") + (position {:x 0 :y 0 :z 0}) + (health 20) + (attack "1d6 + 3")) + +(defn battle-system + [entity] + (let [opponent (if (= (name entity) "Goblin") + (find-by :name "Adventurer") + (find-by :name "Goblin"))] + (health opponent (max 0 (- (health opponent) (first (roll (attack entity)))))))) + +(defn do-battle + [] + (let [goblin (find-by :name "Goblin") + adventurer (find-by :name "Adventurer")] + (while (every? pos? [(health goblin) (health adventurer)]) + (run-e battle-system [:name :health])))) (defn -main "I don't do a whole lot ... yet." diff --git a/src/minibaldur/ecs.clj b/src/minibaldur/ecs.clj index 8166e7d..cebae3c 100644 --- a/src/minibaldur/ecs.clj +++ b/src/minibaldur/ecs.clj @@ -36,7 +36,7 @@ (doseq [entity (query-e query)] (apply f entity args))) -(defn find-entity-by +(defn find-by [component value] (some #(and (= value (val %)) (key %)) (@*components* component))) diff --git a/src/minibaldur/engine.clj b/src/minibaldur/engine.clj index 3a217fd..48b79ee 100644 --- a/src/minibaldur/engine.clj +++ b/src/minibaldur/engine.clj @@ -1,19 +1,18 @@ (ns minibaldur.engine) -(defn diceroll +(defn- diceroll [x] - (re-find #"(\d+)d(\d+)" x)) + (if-let [match (re-find #"(\d+)d(\d+)" x)] + (map #(Integer/parseInt %) (next match)))) -(defn diceval +(defn- diceval [x] - (if-let [[_ a b] (diceroll x)] - (apply + (repeat (Integer/parseInt a) - (+ (rand-int (Integer/parseInt b)) 1))) + (if-let [[a b] (diceroll x)] + (apply + (repeat a (inc (rand-int b)))) (Integer/parseInt x))) (defn roll - "Takes a standard ttrpg roll specifier and returns a vector, starting with the sum, and - then each roll in the order listed in the specifier" + "Takes a standard ttrpg roll specifier and returns a vector, starting with the sum, and then each roll in the order listed in the specifier" [specifier] (let [dies-and-ops (clojure.string/split specifier #"\s+") first-die-val (diceval (first dies-and-ops)) @@ -28,3 +27,17 @@ "+" (recur (+ sum val) (if roll? (conj rolls val) rolls) (nnext tail)) "-" (recur (- sum val) (if roll? (conj rolls val) rolls) (nnext tail)))) (into [sum] rolls))))) + +(defn roll-advantage + "Rolls 2d20 and returns the highest. Takes an optional specifier for bonuses" + ([] (max-key first (roll "1d20") (roll "1d20"))) + ([bonuses] + (let [spec (str "1d20 + " bonuses)] + (max-key first (roll spec) (roll spec))))) + +(defn roll-disadvantage + "Rolls 2d20 and returns the lowest. Takes an optional specifier for bonuses" + ([] (min-key first (roll "1d20") (roll "1d20"))) + ([bonuses] + (let [spec (str "1d20 + " bonuses)] + (min-key first (roll spec) (roll spec))))) diff --git a/test/minibaldur/ecs_test.clj b/test/minibaldur/ecs_test.clj index 78db68c..88d9743 100644 --- a/test/minibaldur/ecs_test.clj +++ b/test/minibaldur/ecs_test.clj @@ -19,7 +19,7 @@ (deftest basic (run-e age-up :age) - (is (= 28 (age (find-entity-by :name "Dane"))))) + (is (= 28 (age (find-by :name "Dane"))))) (defcomponent alignment) (defcomponent health) @@ -45,5 +45,5 @@ (deftest full (run-e damage-evil-creatures [:alignment :health] 2) - (is (= 2 (health (find-entity-by :name "Fey")))) - (is (= 8 (health (find-entity-by :name "Goblin"))))) + (is (= 2 (health (find-by :name "Fey")))) + (is (= 8 (health (find-by :name "Goblin")))))