add parser code from old test project sources

This commit is contained in:
Gered 2016-02-27 16:14:16 -05:00
parent 0fa64f5ab7
commit ea795f0d34
30 changed files with 4390 additions and 1 deletions

View file

@ -6,4 +6,5 @@
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/tools.logging "0.3.1"]
[log4j "1.2.16"]])
[log4j "1.2.16"]
[cheshire "5.5.0"]])

View file

@ -0,0 +1,38 @@
{"Lucifron" {:entities {"Lucifron" {:count 1}
"Flamewaker Protector" {:count 2}}}
"Magmadar" {:entities {"Magmadar" {:count 1}}}
"Gehennas" {:entities {"Gehennas" {:count 1}
"Flamewaker" {:count 2}}}
"Garr" {:entities {"Garr" {:count 1}
"Firesworn" {:count 8}}}
"Baron Geddon" {:entities {"Baron Geddon" {:count 1}}}
"Shazzrah" {:entities {"Shazzrah" {:count 1}}}
"Sulfuron Harbinger" {:entities {"Sulfuron Harbinger" {:count 1}
"Flamewaker Priest" {:count 4}}}
"Golemagg the Incinerator" {:entities {"Golemagg the Incinerator" {:count 1}
"Core Rager" {:count 2}}}
"Majordomo Executus" {:entities {"Majordomo Executus" {:count 1
:must-kill-count 0
:ignore-interactions-with ["Ragnaros"]
:ignore-skills ["Summon Ragnaros"]}
"Flamewaker Healer" {:count 4}
"Flamewaker Elite" {:count 4}}
:trigger-on-damage? true
:trigger-on-debuff? true}
"Ragnaros" {:entities {"Ragnaros" {:count 1
:ignore-interactions-with ["Majordomo Executus"]}
"Son of Flame" {:count 8
:must-kill-count 0}}
:trigger-on-damage? true
:trigger-on-debuff? true}
"Onyxia" {:entities {"Onyxia" {:count 1}}}}

View file

@ -0,0 +1,3 @@
Hunter's Mark
Detect Magic
Mind Soothe

View file

@ -0,0 +1,4 @@
Hunter's Mark
Detect Magic
Mind Soothe
Distract

View file

@ -0,0 +1,89 @@
"Plucky" Johnson's Human Form
Alzzin's Minion
Antu'sul
Anub'shiah
Arin'sor
Arugal's Voidwalker
Atal'ai Deathwalker's Spirit
Chok'sul
Commander Gor'shak
Darkreaver's Fallen Charger
Death's Head Acolyte
Death's Head Adept
Death's Head Cultist
Death's Head Geomancer
Death's Head Necromancer
Death's Head Priest
Death's Head Sage
Death's Head Seer
Death's Head Ward Keeper
Doctor Weavil's Flying Machine
Dreka'Sur
Eliza's Guard
Faldreas Goeth'Shael
Father Winter's Helper
Fellicent's Shade
Flik's Frog
Franclorn's Spirit
Gizlock's Dummy
Great-father Winter's Helper
Greatfather Winter's Helper
Gunther's Visage
Guse's War Rider
Hammertoe's Spirit
Helcular's Remains
Hukku's Imp
Hukku's Succubus
Hukku's Voidwalker
Ichman's Gryphon
Jen'shan
Jezelle's Felhunter
Jezelle's Felsteed
Jezelle's Imp
Jezelle's Succubus
Jezelle's Voidwalker
Jeztor's War Rider
Jin'sora
Jugkar Grim'rod's Image
Krakle's Thermometer
Kurzen's Agent
Lord Azrethoc's Image
Maiden's Virtue Crewman
Merithra's Wake
Mulverick's War Rider
Nefarian's Troops
Nijel's Point Guard
Noxxion's Spawn
Officer Vu'Shalay
Onyxia's Elite Guard
Rak'shiri
Ralo'shan the Eternal Watcher
Ribbly's Crony
Ryson's Eye in the Sky
Sartura's Royal Guard
Sentinel Glynda Nal'Shea
Sergeant Ba'sha
Servant of Antu'sul
Sharpbeak's Father
Sharpbeak's Mother
Slidore's Gryphon
Slim's Friend
Sneed's Shredder
Sri'skulk
The Master's Eye
Twilight's Hammer Ambassador
Twilight's Hammer Executioner
Twilight's Hammer Torturer
Tyrion's Spybot
Umi's Mechanical Yeti
Varo'then's Ghost
Vipore's Gryphon
Warug's Bodyguard
Warug's Target Dummy
Winna's Kitten
Winter's Little Helper
Wizzlecrank's Shredder
Wrenix's Gizmotronic Apparatus
Xiggs Fuselighter's Flyingmachine
Ysida's Trigger
Zaetar's Spirit

View file

@ -0,0 +1,464 @@
(ns vwowrla.core.encounters
(:import
(java.util Date))
(:require
[clojure.java.io :as io]
[clojure.tools.logging :refer [info error]]
[cheshire.core :as json])
(:use
vwowrla.core.utils))
(def defined-encounters (get-edn-resource "encounters.edn"))
(def non-combat-starting-auras (get-text-resource-as-lines "non_combat_starting_auras.txt"))
(def non-combat-starting-skills (get-text-resource-as-lines "non_combat_starting_skills.txt"))
(def wipe-or-timeout-period (* 60 1000))
(declare calculate-encounter-stats)
(declare count-currently-dead)
(declare get-entity-last-activity)
(defn find-defined-encounter-name
"returns the name of a defined encounter which includes the given entity in it's
list of trigger entities. returns nil if there is no encounter which includes the
given entity"
[entity-name]
(->> defined-encounters
(filter (fn [[_ {:keys [entities]}]]
(->> entities
(filter #(= (first %) entity-name))
(first))))
(ffirst)))
(defn find-past-encounters
"return a list of all previously parsed encounters (successful and not) matching the encounter name"
[encounter-name data]
(->> (:encounters data)
(filter #(= (:name %) encounter-name))))
(defn any-successful-encounters?
"returns true if there are any successful parsed encounters matching the encounter name"
[encounter-name data]
(->> (find-past-encounters encounter-name data)
(map :wipe-or-timeout?)
(filter false?)
(empty?)
(not)))
(defn update-active-encounter
"updates the active encounter using function f which will take the current active
encounter and any supplied args, returning a new active encounter which is
'updated' in the original full parsed data and then finally returned."
[data f & args]
(apply update-in data [:active-encounter] f args))
(defn update-all-entities
"updates all entities in the encounter using function f which takes the current
entity and any supplied args, returning a new entity which is 'updated' in the
original encounter. returns the encounter with the modified entity data."
[encounter f & args]
(reduce
(fn [encounter [entity-name entity]]
(assoc-in encounter [:entities entity-name] (apply f entity args)))
encounter
(:entities encounter)))
(defn update-all-active-encounter-entities
"updates all entities in the current active encounter in the full parsed data
using function f which takes the current entity and any supplied args, returning
a new entity which is 'updated' in the original encounter. returns the updated
full parsed data."
[data f & args]
(update-active-encounter data #(update-all-entities % f args)))
(defn update-entity
"updates an entity in the full parsed data's active encounter using function f
which takes the current entity and any supplied args, returning the new entity
which is 'updated' in the active encounter. returns the updated full parsed data."
[data entity-name f & args]
(apply update-in data [:active-encounter :entities entity-name] f args))
(defn update-entity-field
"updates a specific field within an entity pointed to by ks in the full parsed
data's active encounter using function f which takes the current entity and any
supplied args, returning the new entity which is 'updated' in the active encounter.
returns the updated full parsed data."
[data entity-name ks f & args]
(apply update-in data (concat [:active-encounter :entities entity-name] ks) f args))
(defn- ignore-interaction?
[entity-name ignore-entity-list {:keys [target-name source-name] :as parsed-line}]
(and (or (= entity-name target-name)
(= entity-name source-name))
(or (contained-in? target-name ignore-entity-list)
(contained-in? source-name ignore-entity-list))))
(defn ignored-interaction-event?
"returns true if the given parsed combat log line is between entities that have
been specified to ignore interactions between for the purposes of detecting
an encounter trigger"
[encounter parsed-line]
(->> (:entities encounter)
(filter
(fn [[entity-name entity-props]]
(seq (:ignore-interactions-with entity-props))))
(filter
(fn [[entity-name entity-props]]
(ignore-interaction? entity-name (:ignore-interactions-with entity-props) parsed-line)))
(seq)))
(defn- ignore-skill?
[entity-name ignore-skill-list {:keys [source-name skill] :as parsed-line}]
(and (= entity-name source-name)
(contained-in? skill ignore-skill-list)))
(defn ignored-skill-event?
"returns true if the given parsed combat log line is for an encounter entity
that is using a skill that has been specifically indicated should be ignored
for the purposes of triggering an encounter"
[encounter parsed-line]
(->> (:entities encounter)
(filter
(fn [[entity-name entity-props]]
(seq (:ignore-skills entity-props))))
(filter
(fn [[entity-name entity-props]]
(ignore-skill? entity-name (:ignore-skills entity-props) parsed-line)))
(seq)))
;;;
;;; encounter start/stop
;;;
(defn detect-encounter-triggered
"determines if the parsed combat log line is for an event involving any specific encounter entities which
should cause an encounter to begin, returning the name of the encounter if it should begin, or nil if no
encounter begin was detected"
[{:keys [target-name source-name damage aura-name type skill] :as parsed-line} data]
(if-let [encounter-name (or (find-defined-encounter-name target-name)
(find-defined-encounter-name source-name))]
(if (and (not (any-successful-encounters? encounter-name data))
(not (contained-in? aura-name non-combat-starting-auras))
(not (contained-in? skill non-combat-starting-skills)))
(let [encounter (get defined-encounters encounter-name)]
(cond
(ignored-interaction-event? encounter parsed-line)
nil
(ignored-skill-event? encounter parsed-line)
nil
; if either of these are defined, then their criteria MUST pass to
; trigger an encounter
(or (:trigger-on-damage? encounter)
(:trigger-on-aura? encounter)
(:trigger-on-buff? encounter)
(:trigger-on-debuff? encounter))
(cond
(and (:trigger-on-damage? encounter) damage) encounter-name
(and (:trigger-on-aura? encounter) aura-name) encounter-name
(and (:trigger-on-buff? encounter) (= :buff type)) encounter-name
(and (:trigger-on-debuff? encounter) (= :debuff type)) encounter-name)
:else
encounter-name)))))
(defn begin-encounter
"sets up a new active encounter in the parsed data, returning the new parsed data set ready to use for
parsing a new encounter."
[encounter-name {:keys [timestamp line] :as parsed-line} data]
(info "Beginning encounter" (str "\"" encounter-name "\"") "detected on line:" line)
(assoc data :active-encounter
{:name encounter-name
:started-at timestamp
:entities {}
:skills {}
:trigger-entities (get-in defined-encounters [encounter-name :entities])}))
(defn detect-encounter-end
"determines if the currently active encounter should end based on the active encounter parsed data.
returns :killed if the encounter should end due to a successful kill, :wipe-or-timeout if the
encounter was found to be over due to a raid wipe or other non-activity timeout, or nil if the
active encounter is not over yet."
[{:keys [^Date timestamp] :as parsed-line} data]
(let [trigger-entites (get-in data [:active-encounter :trigger-entities])]
(cond
(every?
(fn [[entity-name {:keys [count must-kill-count]}]]
(let [count-dead (count-currently-dead data entity-name)]
(>= count-dead (or must-kill-count count))))
trigger-entites)
:killed
(every?
(fn [[entity-name _]]
; HACK: what is the right thing to do when the entity we want to check the activity of hasn't even been
; added to the encounter's entity list yet? most likely because the encounter has probably just begun
; and there have been no combat log lines yet for one or more of the trigger entities.
; should we have a minimum encounter length time? something like 15-30 seconds? that also feels hacky...
(>= (- (.getTime timestamp)
(.getTime (or (get-entity-last-activity entity-name data)
timestamp)))
wipe-or-timeout-period))
trigger-entites)
:wipe-or-timeout)))
(defn end-encounter
"ends the current active encounter in the parsed data, moving it from :active-encounter and inserted it into the
end of the :encounters list. finalizes the encounter by performing various final entity statistic calculations and
marks the encounter as successful or not. returns the new parsed data set without any active encounter set."
[{:keys [timestamp line] :as parsed-line} encounter-end-cause data]
(let [wipe-or-timeout? (= encounter-end-cause :wipe-or-timeout)]
(info "Ending encounter" (str "\"" (get-in data [:active-encounter :name]) "\"") "detected on line:" line)
(if wipe-or-timeout?
(info "Encounter ending due to wipe or trigger entity activity timeout (unsuccessful encounter kill attempt)."))
(let [data (-> data
(update-active-encounter assoc :ended-at timestamp)
(update-active-encounter assoc :wipe-or-timeout? wipe-or-timeout?)
(calculate-encounter-stats))]
(-> data
(assoc-in [:active-encounter] nil)
(update-in [:encounters] #(conj %1 (:active-encounter data)))))))
;;;
;;; entity manipulation
;;;
(defn touch-entity
"updates an entity within the current active encounter by resetting it's :last-activity-at timestamp
or adds a new entity under the given name to the active encounter if it does not already exist. returns
the new parsed data set with the updated entity information."
[data entity-name timestamp]
(if-not (get-in data [:active-encounter :entities entity-name])
(assoc-in data [:active-encounter :entities entity-name]
{:name entity-name
:added-at timestamp
:last-activity-at timestamp
:damage-out-total 0
:damage-out-totals {}
:damage-in-total 0
:damage-in-totals {}
:alive-dps 0
:encounter-dps 0
:damage-out {}
:damage-out-by-entity {}
:damage-in {}
:damage-in-by-entity {}
:casts {}
:other-powers {}
:auras {}
:deaths []
:resurrections []
:alive-duration 0})
(assoc-in data [:active-encounter :entities entity-name :last-activity-at] timestamp)))
(defn get-entity-last-activity
[entity-name data]
(get-in data [:active-encounter :entities entity-name :last-activity-at]))
(defn get-entity-alive-time
"returns the number of milliseconds of the encounter that the entity was alive for"
[{:keys [deaths resurrections] :as entity} {:keys [started-at ended-at] :as encounter}]
;(println (:name entity))
;(println "started-at" started-at)
;(println "ended-at " ended-at)
;(println "deaths " deaths)
;(println "resurrects" resurrections)
(if (and (= 0 (count deaths))
(= 0 (count resurrections)))
(:duration encounter)
(let [segments (as-> (concat
(map (fn [death] {:status :dead :at (:timestamp death)}) deaths)
(map (fn [resurrection] {:status :alive :at (:timestamp resurrection)}) resurrections)
[{:status :end :at ended-at}]) x
(remove empty? x)
(sort-by :at x))]
;(println ">" segments)
(reduce
(fn [{:keys [total current-status from] :as result} {:keys [status at]}]
;(println ">>" current-status from status at)
(cond
; is the first state change we find a resurrect? (e.g. they were dead when the fight began)
(and (nil? current-status)
(= :alive status))
(assoc result
:current-status :alive
:from at)
; first state change we find is a death
(and (nil? current-status)
(= :dead status))
(assoc result
:current-status :dead
:from at
:total (+ total (time-between from at)))
; resurrected after a death
(and (= :dead current-status)
(= :alive status))
(assoc result
:current-status :alive
:from at)
; another death state when already dead? this can happen if there are multiple entities in the encounter
; with the same name. pretty much impossible to separate them with just the info in the combat log
; available to us. so, we just tack on the time since the last death since at least one of the entities
; was alive for that entire time period. in this way, the "entity alive time" for the entity with this
; name will just be a counter of "at least one entity with this name was alive"
(and (= :dead current-status)
(= :dead status))
(assoc result
:from at
:total (+ total (time-between from at)))
; fight has ended (always should be the last iteration, just return the total value here)
(= :end status)
(if (= :dead current-status)
total
(+ total (time-between from at)))))
{:total 0
:from started-at}
segments))))
(defn finalize-entity-auras
[entity timestamp]
; TODO
entity)
(defn finalize-entities
[data]
(update-active-encounter
data
(fn [encounter]
(-> encounter
(update-all-entities
#(assoc % :alive-duration (get-entity-alive-time % encounter)))
(update-all-entities
#(assoc %
:encounter-dps (Math/round ^double
(/ (:damage-out-total %)
(/ (:duration encounter)
1000)))
:alive-dps (Math/round ^double
(/ (:damage-out-total %)
(/ (:alive-duration %)
1000)))))
(update-all-entities finalize-entity-auras (:ended-at encounter))))))
(defn calculate-encounter-stats
[data]
(-> data
(update-active-encounter
(fn [{:keys [started-at ended-at] :as encounter}]
(assoc encounter :duration (time-between started-at ended-at))))
(finalize-entities)))
(defn count-currently-dead
[data entity-name]
(if-let [entity (get-in data [:active-encounter :entities entity-name])]
(let [num-deaths (count (:deaths entity))
num-resurrects (count (:resurrections entity))]
(- num-deaths num-resurrects))
0))
(defn update-damage-averages
[{:keys [num-hits total-hit-damage total-crit-damage num-crits] :as totals}]
(-> totals
(update-in [:average-hit] #(if (> num-hits 0) (int (/ total-hit-damage num-hits)) %))
(update-in [:average-crit] #(if (> num-crits 0) (int (/ total-crit-damage num-crits)) %))))
(defn add-from-damage-properties
[totals
{:keys [damage damage-type hit-type crit? partial-absorb partial-resist partial-block avoidance-method] :as damage-properties}]
(let [damage (or damage 0)]
(-> (or totals {:damage 0
:max-hit 0
:min-hit 0
:total-hit-damage 0
:average-hit 0
:max-crit 0
:min-crit 0
:total-crit-damage 0
:average-crit 0
:num-total-hits 0
:num-hits 0
:num-crits 0
:num-glancing 0
:num-crushing 0
:num-partial-absorb 0
:num-partial-resist 0
:num-partial-block 0
:num-miss 0
:num-dodge 0
:num-parry 0
:num-resist 0
:num-absorb 0
:num-evade 0
:num-immune 0})
(update-in [:damage] #(+ % damage))
(update-in [:max-hit] #(if (and (not crit?) (not avoidance-method)) (max % damage) %))
(update-in [:min-hit] #(if (and (not crit?) (not avoidance-method)) (if (> damage 0) (if (= % 0) damage (min % damage)) %) %))
(update-in [:total-hit-damage] #(if (and (not crit?) (not avoidance-method)) (+ % damage) %))
(update-in [:max-crit] #(if (and crit? (not avoidance-method)) (max % damage) %))
(update-in [:min-crit] #(if (and crit? (not avoidance-method)) (if (> damage 0) (if (= % 0) damage (min % damage)) %) %))
(update-in [:total-crit-damage] #(if (and crit? (not avoidance-method)) (+ % damage) %))
(update-in [:num-total-hits] #(if-not avoidance-method (inc %) %))
(update-in [:num-hits] #(if (and (not avoidance-method) (not crit?)) (inc %) %))
(update-in [:num-crits] #(if (and (not avoidance-method) crit?) (inc %) %))
(update-in [:num-glancing] #(if (= hit-type :glancing) (inc %) %))
(update-in [:num-crushing] #(if (= hit-type :crushing) (inc %) %))
(update-in [:num-partial-absorb] #(if partial-absorb (inc %) %))
(update-in [:num-partial-resist] #(if partial-resist (inc %) %))
(update-in [:num-partial-block] #(if partial-block (inc %) %))
(update-in [:num-miss] #(if (= avoidance-method :miss) (inc %) %))
(update-in [:num-dodge] #(if (= avoidance-method :dodge) (inc %) %))
(update-in [:num-parry] #(if (= avoidance-method :parry) (inc %) %))
(update-in [:num-resist] #(if (= avoidance-method :resist) (inc %) %))
(update-in [:num-absorb] #(if (= avoidance-method :absorb) (inc %) %))
(update-in [:num-evade] #(if (= avoidance-method :evade) (inc %) %))
(update-in [:num-immune] #(if (= avoidance-method :immune) (inc %) %))
(update-damage-averages))))
(defn entity-takes-damage
[data entity-name from-entity-name {:keys [skill damage damage-type] :as damage-properties} timestamp]
(-> data
(update-entity-field entity-name [:damage-in-total] #(if damage (+ (or % 0) damage) %))
(update-entity-field entity-name [:damage-in-totals damage-type] #(if damage (+ (or % 0) damage) %))
(update-entity-field entity-name [:damage-in skill] #(add-from-damage-properties % damage-properties))
(update-entity-field entity-name [:damage-in-by-entity from-entity-name skill] #(add-from-damage-properties % damage-properties))))
(defn entity-deals-damage
[data entity-name to-entity-name {:keys [skill damage damage-type] :as damage-properties} timestamp]
(-> data
(update-entity-field entity-name [:damage-out-total] #(if damage (+ (or % 0) damage) %))
(update-entity-field entity-name [:damage-out-totals damage-type] #(if damage (+ (or % 0) damage) %))
(update-entity-field entity-name [:damage-out skill] #(add-from-damage-properties % damage-properties))
(update-entity-field entity-name [:damage-out-by-entity to-entity-name skill] #(add-from-damage-properties % damage-properties))))
;;;
;;; main combat log entry processing entry points
;;;
(defn process-source-to-target-damage
[source-name target-name damage-properties timestamp data]
(-> data
(touch-entity source-name timestamp)
(touch-entity target-name timestamp)
(entity-takes-damage target-name source-name damage-properties timestamp)
(entity-deals-damage source-name target-name damage-properties timestamp))
)
(defn process-entity-death
[entity-name timestamp data]
(-> data
(touch-entity entity-name timestamp)
(update-entity-field entity-name [:deaths] #(conj % {:timestamp timestamp}))
(update-entity entity-name finalize-entity-auras timestamp)))
(defn process-source-to-target-cast
[source-name target-name skill-name timestamp data]
data)
(defn process-entity-cast
[entity-name skill-name timestamp data]
data)

View file

@ -0,0 +1,161 @@
(ns vwowrla.core.handlers
(:require
[vwowrla.core.encounters :as encounters]))
(defmulti handle-event
(fn [{:keys [event]} _]
(keyword event)))
(defmethod handle-event :skill-damage-to-target
[{:keys [source-name skill target-name damage damage-type absorbed resisted blocked crit? timestamp] :as parsed} data]
(encounters/process-source-to-target-damage
source-name
target-name
{:skill skill
:actual-skill? true
:damage damage
:damage-type (or damage-type :physical)
:crit? crit?
:partial-absorb absorbed
:partial-resist resisted
:partial-block blocked}
timestamp
data))
(defmethod handle-event :skill-avoided-by-target
[{:keys [source-name target-name skill avoidance-method timestamp] :as parsed} data]
(encounters/process-source-to-target-damage
source-name
target-name
{:skill skill
:actual-skill? true
:avoidance-method avoidance-method}
timestamp
data))
(defmethod handle-event :damage-reflected
[{:keys [source-name target-name damage damage-type timestamp] :as parsed} data]
(encounters/process-source-to-target-damage
source-name
target-name
{:skill "Reflect"
:actual-skill? false
:damage damage
:damage-type damage-type
:crit? false}
timestamp
data))
(defmethod handle-event :melee-damage-to-target
[{:keys [source-name target-name damage damage-type hit-type absorbed resisted blocked crit? timestamp] :as parsed} data]
(encounters/process-source-to-target-damage
source-name
target-name
{:skill "Melee"
:actual-skill? false
:damage damage
:damage-type (or damage-type :physical)
:hit-type hit-type
:crit? crit?
:partial-absorb absorbed
:partial-resist resisted
:partial-block blocked}
timestamp
data))
(defmethod handle-event :melee-avoided-by-target
[{:keys [source-name target-name avoidance-method timestamp] :as parsed} data]
(encounters/process-source-to-target-damage
source-name
target-name
{:skill "Melee"
:actual-skill? false
:avoidance-method avoidance-method}
timestamp
data))
(defmethod handle-event :skill-interrupted-by-target
[{:keys [source-name target-name skill timestamp] :as parsed} data]
data)
(defmethod handle-event :dot-damages-target
[{:keys [source-name skill target-name damage damage-type absorbed resisted timestamp] :as parsed} data]
(encounters/process-source-to-target-damage
source-name
target-name
{:skill skill
:actual-skill? true
:damage damage
:damage-type damage-type
:crit? false
:partial-absorb absorbed
:partial-resist resisted}
timestamp
data))
(defmethod handle-event :cast-begins
[{:keys [source-name skill spell? timestamp] :as parsed} data]
; don't think we really care about this ?
data)
(defmethod handle-event :skill-performed-on-target
[{:keys [source-name target-name skill spell? extra timestamp] :as parsed} data]
(encounters/process-source-to-target-cast source-name target-name skill timestamp data))
(defmethod handle-event :cast
[{:keys [source-name skill spell? timestamp] :as parsed} data]
(encounters/process-entity-cast source-name skill timestamp data))
(defmethod handle-event :skill-heals-target
[{:keys [source-name skill crit? target-name amount timestamp] :as parsed} data]
data)
(defmethod handle-event :resource-gained
[{:keys [target-name amount resource-type source-name skill timestamp] :as parsed} data]
data)
(defmethod handle-event :resource-lost
[{:keys [target-name amount resource-type source-name skill timestamp] :as parsed} data]
(condp = resource-type
:health (encounters/process-source-to-target-damage
source-name
target-name
{:skill skill
:actual-skill? true
:damage amount
:damage-type :physical
:crit? false}
timestamp
data)
data))
(defmethod handle-event :special-gained
[{:keys [target-name special source timestamp] :as parsed} data]
data)
(defmethod handle-event :aura-gained
[{:keys [target-name aura-name type stacks timestamp] :as parsed} data]
data)
(defmethod handle-event :aura-lost
[{:keys [target-name aura-name faded? stacks timestamp] :as parsed} data]
data)
(defmethod handle-event :other-damage
[{:keys [target-name damage damage-type resisted absorbed source timestamp] :as parsed} data]
data)
(defmethod handle-event :death
[{:keys [source-name timestamp] :as parsed} data]
(encounters/process-entity-death source-name timestamp data))
(defmethod handle-event :ignored
[{:keys [line] :as parsed} data]
#_(println "[WARN] *** IGNORED ***" line)
data)
(defmethod handle-event :default
[{:keys [line] :as parsed} data]
(println "[WARN] *** UNRECOGNIZED ***" line)
data)

View file

@ -0,0 +1,765 @@
(ns vwowrla.core.matchers
(:use
vwowrla.core.utils))
;;; *** IMPORTANT!! ***
;;; The order that the matchers are listed is **NOT** completely arbitrary!!
;;; Some of the regex patterns won't ever have a problem matching some line they shouldn't, but some others
;;; can match the wrong lines if the regex patterns appear after others. e.g. the skill/spell and melee patterns.
;;; The unit tests should pick this up if something gets moved out of the proper order, but be very careful!!
(def regex-matchers
[
;;; ---------------------------------------------------------------------------------------------
;;; CATCH-ALL REGEX MATCHERS
;;; These are only here to prevent extra "unrecognized" warnings while parsing logs for messages
;;; that we simply don't care at all about.
;;; NOTE: these are at the beginning so we catch them first and move on. otherwise some could
;;; potentially get caught and misinterpreted as other types of combat log messages
{:event :ignored :regex #"^You fail to cast (.+): (.+)\.$"}
{:event :ignored :regex #"^You fail to perform (.+): (.+)\.$"}
{:event :ignored :regex #"^You have slain (.+)!$"}
{:event :ignored :regex #"^(.+) is slain by (.+)!$"}
{:event :ignored :regex #"^(.+) (?:creates|create) (.+)\.$"}
{:event :ignored :regex #"^Your pet begins eating a (.+)\.$"}
{:event :ignored :regex #"^(.+)'s pet begins eating a (.+)\.$"}
{:event :ignored :regex #"^Your (.+) is reflected back by (.+)\.$"}
{:event :ignored :regex #"^(.+?)'s (.+) is reflected back by (.+)\.$"}
{:event :ignored :regex #"^(.+) is destroyed\.$"}
{:event :ignored :regex #"^Your (.+) reputation has increased by (\d+)\.$"}
{:event :ignored :regex #"^Your equipped items suffer a 10% durability loss\.$"}
{:event :ignored :regex #"^(.+) dies, honorable kill (.+)$"}
; TODO: keep an eye on these types of entries. seems safe to ignore so far with Onyxia + MC though...
{:event :ignored :regex #"^(.+) is killed by (.+)\.$"}
;;; ---------------------------------------------------------------------------------------------
;;; SKILL/SPELL DAMAGE
{:regex #"^Your (.+) (hits|crits) (.+) for (\d+) (.+) damage\.(?: \((\d+) resisted\))?(?: \((\d+) absorbed\))?$"
:id :skill-damages-target-elemental-self
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:args #(hash-map
:skill %1
:crit? (= %2 "crits")
:target-name %3
:damage (->int %4)
:damage-type (->kw %5)
:resisted (->int %6)
:absorbed (->int %7)
:source-name "you")}
{:regex #"^Your (.+) (hits|crits) (.+) for (\d+) damage\.(?: \((\d+) blocked\))?(?: \((\d+) absorbed\))?$"
:id :skill-damages-target-self
:logfmt :skill-damages-target
:event :skill-damage-to-target
:args #(hash-map
:skill %1
:crit? (= %2 "crits")
:target-name %3
:damage (->int %4)
:blocked (->int %5)
:absorbed (->int %6)
:source-name "you")}
{:regex #"^Your (.+) (hits|crits) (.+) for (\d+)\.(?: \((\d+) blocked\))?(?: \((\d+) absorbed\))?$"
:id :skill-damages-target-short-self
:logfmt :skill-damages-target-short
:event :skill-damage-to-target
:args #(hash-map
:skill %1
:crit? (= %2 "crits")
:target-name %3
:damage (->int %4)
:blocked (->int %5)
:absorbed (->int %6)
:source-name "you")}
{:regex #"^(.+?)'s (.+) (hits|crits) (.+) for (\d+) (.+) damage\.(?: \((\d+) resisted\))?(?: \((\d+) absorbed\))?$"
:id :skill-damages-target-elemental
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:args #(hash-map
:source-name %1
:skill %2
:crit? (= %3 "crits")
:target-name %4
:damage (->int %5)
:damage-type (->kw %6)
:resisted (->int %7)
:absorbed (->int %8))}
; TODO: is this ever emitted in a combat log? why did i add this one... ?
{:regex #"^(.+?)'s (.+) (hits|crits) (.+) for (\d+) damage\.(?: \((\d+) blocked\))?(?: \((\d+) absorbed\))?$"
:id :skill-damages-target
:logfmt :skill-damages-target
:event :skill-damage-to-target
:args #(hash-map
:source-name %1
:skill %2
:crit? (= %3 "crits")
:target-name %4
:damage (->int %5)
:blocked (->int %6)
:absorbed (->int %7))}
{:regex #"^(.+?)'s (.+) (hits|crits) (.+) for (\d+)\.(?: \((\d+) blocked\))?(?: \((\d+) absorbed\))?$"
:id :skill-damages-target-short
:logfmt :skill-damages-target-short
:event :skill-damage-to-target
:args #(hash-map
:source-name %1
:skill %2
:crit? (= %3 "crits")
:target-name %4
:damage (->int %5)
:blocked (->int %6)
:absorbed (->int %7))}
;;; ---------------------------------------------------------------------------------------------
;;; SKILL/SPELL MISSES / FULL-ABSORBS / FULL-RESISTS
{:regex #"^Your (.+) missed (.+)\.$"
:id :skill-miss-self
:logfmt :skill-miss
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :miss)}
{:regex #"^(.+?)'s (.+) (?:missed|misses) (.+)\.$"
:id :skill-miss
:logfmt :skill-miss
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :miss)}
{:regex #"^Your (.+) was parried by (.+)\.$"
:id :skill-parry-self
:logfmt :skill-parry
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :parry)}
{:regex #"^(.+?)'s (.+) was parried by (.+)\.$"
:id :skill-parry
:logfmt :skill-parry
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :parry)}
{:regex #"^(.+?)'s (.+) was parried\.$"
:id :skill-parry-implied-self
:logfmt :skill-parry
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name "you"
:avoidance-method :parry)}
{:regex #"^Your (.+) was blocked by (.+)\.$"
:id :skill-block-self
:logfmt :skill-block
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :block)}
{:regex #"^(.+?)'s (.+) was blocked by (.+)\.$"
:id :skill-block
:logfmt :skill-block
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :block)}
{:regex #"^Your (.+) was dodged by (.+)\.$"
:id :skill-dodge-self
:logfmt :skill-dodge
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :dodge)}
{:regex #"^(.+?)'s (.+) was dodged by (.+)\.$"
:id :skill-dodge
:logfmt :skill-dodge
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :dodge)}
{:regex #"^(.+?)'s (.+) was dodged\.$"
:id :skill-dodge-implied-self
:logfmt :skill-dodge
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name "you"
:avoidance-method :dodge)}
{:regex #"^Your (.+) was evaded by (.+)\.$"
:id :skill-evade-self
:logfmt :skill-evade
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :evade)}
{:regex #"^(.+?)'s (.+) was evaded by (.+)\.$"
:id :skill-evade
:logfmt :skill-evade
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :evade)}
{:regex #"^(.+) (?:resist|resists) your (.+)\.$"
:id :skill-resist-self
:logfmt :skill-resist
:event :skill-avoided-by-target
:args #(hash-map
:target-name %1
:skill %2
:source-name "you"
:avoidance-method :resist)}
{:regex #"^(.+?) (?:resist|resists) (.+?)'s (.+)\.$"
:id :skill-resist
:logfmt :skill-resist
:event :skill-avoided-by-target
:args #(hash-map
:target-name %1
:source-name %2
:skill %3
:avoidance-method :resist)}
; i don't think target is ever "you" for this one
{:regex #"^(.+?)'s (.+) is absorbed by (.+)\.$"
:id :skill-absorb
:logfmt :skill-absorb
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :absorb)}
{:regex #"^Your (.+) is absorbed by (.+)\.$"
:id :skill-absorb-self
:logfmt :skill-absorb
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :absorb)}
{:regex #"^(.+?) (?:absorb|absorbs) (.+?)'s (.+)\.$"
:id :skill-absorb-2
:logfmt :skill-absorb-2
:event :skill-avoided-by-target
:args #(hash-map
:target-name %1
:source-name %2
:skill %3
:avoidance-method :absorb)}
; i don't think target is ever "you" for this one
{:regex #"^(.+?)'s (.+) was resisted by (.+)\.$"
:id :skill-resist-2
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :resist)}
{:regex #"^Your (.+) was resisted by (.+)\.$"
:id :skill-resist-2-self
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :resist)}
{:regex #"^(.+?)'s (.+) was resisted\.$"
:id :skill-resist-implied-self
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name "you"
:avoidance-method :resist)}
{:regex #"^Your (.+) failed\. (.+) is immune\.$"
:id :skill-immune-self
:logfmt :skill-immune
:event :skill-avoided-by-target
:args #(hash-map
:skill %1
:target-name %2
:source-name "you"
:avoidance-method :immune)}
{:regex #"^(.+?)'s (.+) fails\. (.+) is immune\.$"
:id :skill-immune
:logfmt :skill-immune
:event :skill-avoided-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name %3
:avoidance-method :immune)}
;;; ---------------------------------------------------------------------------------------------
;;; REFLECTS
{:regex #"^(.+) (?:reflects|reflect) (\d+) (.+) damage to (.+)\.$"
:id :target-reflects-elemental-damage
:logfmt :target-reflects-elemental-damage
:event :damage-reflected
:args #(hash-map
:source-name %1
:damage (->int %2)
:damage-type (->kw %3)
:target-name %4)}
;;; ---------------------------------------------------------------------------------------------
;;; MELEE DAMAGE
{:regex #"^(.+) (hit|hits|crit|crits) (.+) for (\d+)\.(?: \((glancing)\))?(?: \((crushing)\))?(?: \((\d+) blocked\))?(?: \((\d+) absorbed\))?$"
:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:args #(hash-map
:source-name %1
:crit? (one-of? %2 "crit" "crits")
:target-name %3
:damage (->int %4)
:hit-type (cond
(= %5 "glancing") :glancing
(= %6 "crushing") :crushing)
:blocked (->int %7)
:absorbed (->int %8))}
{:regex #"^(.+) (hit|hits|crit|crits) (.+) for (\d+) (.+) damage\.(?: \((glancing)\))?(?: \((crushing)\))?(?: \((\d+) resisted\))?(?: \((\d+) absorbed\))?$"
:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:args #(hash-map
:source-name %1
:crit? (one-of? %2 "crit" "crits")
:target-name %3
:damage (->int %4)
:damage-type (->kw %5)
:hit-type (cond
(= %6 "glancing") :glancing
(= %7 "crushing") :crushing)
:resisted (->int %8)
:absorbed (->int %9))}
;;; ---------------------------------------------------------------------------------------------
;;; MELEE DAMAGE AVOIDANCE (ABSORB/RESIST/MISS/BLOCK/DODGE/PARRY/EVADE)
{:regex #"^(.+) (?:attack|attacks)\. (.+) (?:absorb|absorbs) all the damage\.$"
:id :melee-full-absorb
:logfmt :melee-full-absorb
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :absorb)}
{:regex #"^(.+) (?:attack|attacks)\. (.+) (?:resist|resists) all the damage\.$"
:id :melee-full-resist
:logfmt :melee-full-resist
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :resist)}
{:regex #"^(.+) (?:miss|misses) (.+)\.$"
:id :melee-miss
:logfmt :melee-miss
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :miss)}
{:regex #"^(.+) (?:attack|attacks)\. (.+) (?:parry|parries)\.$"
:id :melee-parry
:logfmt :melee-parry
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :parry)}
{:regex #"^(.+) (?:attack|attacks)\. (.+) (?:dodge|dodges)\.$"
:id :melee-dodge
:logfmt :melee-dodge
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :dodge)}
{:regex #"^(.+) (?:attack|attacks)\. (.+) (?:block|blocks)\.$"
:id :melee-block
:logfmt :melee-block
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :block)}
{:regex #"^(.+) (?:attack|attacks)\. (.+) (?:evade|evades)\.$"
:id :melee-evade
:logfmt :melee-evade
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :evade)}
{:regex #"^(.+) (?:attacks|attack) but (.+) is immune\.$"
:id :melee-immune
:logfmt :melee-immune
:event :melee-avoided-by-target
:args #(hash-map
:source-name %1
:target-name %2
:avoidance-method :immune)}
;;; ---------------------------------------------------------------------------------------------
;;; SPELL INTERRUPTION
{:regex #"^(.+?) (?:interrupts|interrupt) (.+?)'s (.+)\.$"
:id :skill-interrupt
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:args #(hash-map
:source-name %1
:target-name %2
:skill %3)}
{:regex #"^(.+) (?:interrupts|interrupt) your (.+)\.$"
:id :skill-interrupt-self
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:args #(hash-map
:source-name %1
:skill %2
:target-name "you")}
;;; ---------------------------------------------------------------------------------------------
;;; DOT
;;; Note that these are not used for just DoT's in the traditional sense (e.g. from applied debuffs, such as curses)
;;; but also channeled spells such as Blizzard / Arcane Missle ticks generate these same combat log events.
{:regex #"^(.+?) (?:suffers|suffer) (\d+) (.+?) damage from (.+?)'s (.+)\.(?: \((\d+) resisted\))?(?: \((\d+) absorbed\))?$"
:id :dot-damages-target
:logfmt :dot-damages-target
:event :dot-damages-target
:args #(hash-map
:target-name %1
:damage (->int %2)
:damage-type (->kw %3)
:source-name %4
:skill %5
:resisted (->int %6)
:absorbed (->int %7))}
{:regex #"^(.+) (?:suffers|suffer) (\d+) (.+) damage from your (.+)\.(?: \((\d+) resisted\))?(?: \((\d+) absorbed\))?$"
:id :dot-damages-target-self
:logfmt :dot-damages-target
:event :dot-damages-target
:args #(hash-map
:target-name %1
:damage (->int %2)
:damage-type (->kw %3)
:skill %4
:resisted (->int %5)
:absorbed (->int %6)
:source-name "you")}
;;; ---------------------------------------------------------------------------------------------
;;; CAST NOTIFICATION / INSTANT CAST ABILITIES
; always source != "you" .. ?
{:regex #"^(.+) (?:begins|begin) to (perform|cast) (.+)\.$"
:id :cast-begins
:logfmt :cast-begins
:event :cast-begins
:args #(hash-map
:source-name %1
:spell? (= %2 "cast")
:skill %3)}
{:regex #"^(.+) (cast|casts|performs|perform) (.+) on (.+): (.+)\.$"
:id :skill-performed-on-target
:logfmt :skill-performed-on-target
:event :skill-performed-on-target
:args #(hash-map
:source-name %1
:spell? (one-of? %2 "casts" "cast")
:skill %3
:target-name %4
:extra %5)}
{:regex #"^(.+) (cast|casts|performs|perform) (.+) on (.+)\.$"
:id :skill-performed-on-target
:logfmt :skill-performed-on-target
:event :skill-performed-on-target
:args #(hash-map
:source-name %1
:spell? (one-of? %2 "casts" "cast")
:skill %3
:target-name %4)}
; only for instant cast stuff .. ?
{:regex #"^(.+) (casts|cast|performs|perform) (.+)\.$"
:id :cast
:logfmt :cast
:event :cast
:args #(hash-map
:source-name %1
:spell? (one-of? %2 "casts" "cast")
:skill %3)}
;;; ---------------------------------------------------------------------------------------------
;;; DIRECT HEALING FROM SKILLS (not HoT's)
{:regex #"^Your (.+?)(?: (critically))? heals (.+) for (\d+)\.$"
:id :skill-heals-target-self
:logfmt :skill-heals-target
:event :skill-heals-target
:args #(hash-map
:skill %1
:crit? (= %2 "critically")
:target-name %3
:amount (->int %4)
:source-name "you")}
{:regex #"^(.+?)'s (.+?)(?: (critically))? heals (.+) for (\d+)\.$"
:id :skill-heals-target
:logfmt :skill-heals-target
:event :skill-heals-target
:args #(hash-map
:source-name %1
:skill %2
:crit? (= %3 "critically")
:target-name %4
:amount (->int %5))}
;;; ---------------------------------------------------------------------------------------------
;;; BONUS HEALING / MANA / RESOURCE REGEN (i.e. not heals, but received via other effects)
{:regex #"^(.+?) (?:gain|gains) (\d+) (health|Mana|Rage|Energy|Happiness) from (.+?)'s (.+)\.$"
:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:args #(hash-map
:target-name %1
:amount (->int %2)
:resource-type (->kw %3)
:source-name %4
:skill %5)}
; apparently for this one, target will never be "you" .. ?
{:regex #"^(.+) (?:gain|gains) (\d+) (health|Mana|Rage|Energy|Happiness) from your (.+)\.$"
:id :resource-gained-from-skill-self
:logfmt :resource-gained-from-skill
:event :resource-gained
:args #(hash-map
:target-name %1
:amount (->int %2)
:resource-type (->kw %3)
:skill %4
:source-name "you")}
; this seems to only ever be for target=you and never for health potions ? the name after
; "from" at the end always seems to refer to a skill, never an entity. "you" seems to always
; be the implied source entity... so basically, target=you and source=you always ... ?
; (for this line, seen mana potions, mana gems, talents that restore mana ...)
{:regex #"^(.+) (?:gain|gains) (\d+) (health|Mana|Rage|Energy|Happiness) from (.+)\.$"
:id :resource-gained
:logfmt :resource-gained
:event :resource-gained
:args #(hash-map
:target-name %1
:amount (->int %2)
:resource-type (->kw %3)
:skill %4
:source-name %1)}
{:regex #"^(.+?)'s (.+) drains (\d+) (health|Mana|Rage|Energy|Happiness) from (.+)\.$"
:id :resource-drained-from-skill
:logfmt :resource-drained-from-skill
:event :resource-lost
:args #(hash-map
:source-name %1
:skill %2
:amount (->int %3)
:resource-type (->kw %4)
:target-name %5)}
; TODO: how does this one look if target=you? does the end bit after "from" just say "you"?
{:regex #"^Your (.+) drains (\d+) (health|Mana|Rage|Energy|Happiness) from (.+)\.$"
:id :resource-drained-from-skill-self
:logfmt :resource-drained-from-skill
:event :resource-lost
:args #(hash-map
:skill %1
:amount (->int %2)
:resource-type (->kw %3)
:target-name %4
:source-name "you")}
;;; ---------------------------------------------------------------------------------------------
;;; OTHER SPECIAL ABILITY/BUFF GAINS
;;; note that these are for things like skill procs or whatever that show up in the combat log
;;; with text similar to that of buffs/debuffs but these are not buffs/debuffs. they need to be
;;; caught first or they will be misinterpreted as buffs by the regex's in the next section
{:regex #"^(.+) (?:gain|gains) (.+) through (.+)\.$"
:id :special-gained
:logfmt :special-gained
:event :special-gained
:args #(hash-map
:target-name %1
:special %2
; NOTE: could be an entity name or a skill/talent name
:source %3)}
;;; ---------------------------------------------------------------------------------------------
;;; BUFF/DEBUFF
{:regex #"^(.+) (?:gain|gains) (.+?)(?: \((\d+)\))?\.$"
:id :aura-buff-gained
:logfmt :aura-buff-gained
:event :aura-gained
:args #(hash-map
:target-name %1
:aura-name %2
:stacks (->int %3)
:type :buff)}
{:regex #"^(.+) (?:is|are) afflicted by (.+?)(?: \((\d+)\))?\.$"
:id :aura-debuff-gained
:logfmt :aura-debuff-gained
:event :aura-gained
:args #(hash-map
:target-name %1
:aura-name %2
:stacks (->int %3)
:type :debuff)}
{:regex #"^(.+) fades from (.+)\.$"
:id :aura-fades
:logfmt :aura-fades
:event :aura-lost
:args #(hash-map
:aura-name %1
:target-name %2
:faded? true)}
{:regex #"^Your (.+) is removed\.$"
:id :aura-removed-self
:logfmt :aura-removed
:event :aura-lost
:args #(hash-map
:aura-name %1
:target-name "you"
:faded? false)}
{:regex #"^(.+?)'s (.+) is removed\.$"
:id :aura-removed
:logfmt :aura-removed
:event :aura-lost
:args #(hash-map
:target-name %1
:aura-name %2
:faded? false)}
;;; ---------------------------------------------------------------------------------------------
;;; ENVIRONMENTAL / OTHER DAMAGE
{:regex #"^(.+) (?:suffers|suffer) (\d+) points of (.+) damage\.(?: \((\d+) resisted\))?(?: \((\d+) absorbed\))?$"
:id :environmental-damage
:logfmt :environmental-damage
:event :other-damage
:args #(hash-map
:target-name %1
:damage (->int %2)
:damage-type (->kw %3)
:resisted (->int %4)
:absorbed (->int %5))}
{:regex #"^(.+) (?:lose|loses) (\d+) health for swimming in lava\.(?: \((\d+) resisted\))?(?: \((\d+) absorbed\))?$"
:id :lava-swim-damage
:logfmt :lava-swim-damage
:event :other-damage
:args #(hash-map
:target-name %1
:damage (->int %2)
:resisted (->int %3)
:absorbed (->int %4)
:damage-type :fire
:source "Swimming in lava")}
{:regex #"^(.+) (?:fall|falls) and (?:lose|loses) (\d+) health\.$"
:id :fall-damage
:logfmt :fall-damage
:event :other-damage
:args #(hash-map
:damage (->int %2)
:target-name %1
:source "Falling")}
;;; ---------------------------------------------------------------------------------------------
;;; DEATH
{:regex #"^(.+) (?:die|dies)\.$"
:id :death
:logfmt :death
:event :death
:args #(hash-map
:source-name %1)}
])

View file

@ -0,0 +1,86 @@
(ns vwowrla.core.parser
(:import (java.util TimeZone))
(:require
[clojure.tools.logging :refer [info error warn]]
[clojure.java.io :as io]
[vwowrla.core.encounters :as encounters]
[vwowrla.core.handlers :refer [handle-event]]
[vwowrla.core.matchers :refer [regex-matchers]])
(:use
vwowrla.core.preparsing
vwowrla.core.utils))
(defn active-encounter?
[data]
(not (nil? (:active-encounter data))))
(defn parse-line
[^String line {:keys [log-owner-char-name] :as options}]
(let [[timestamp stripped-line] (split-log-timestamp-and-content line)
sanitized-line (-> stripped-line
(undo-swstats-fixlogstring)
(sanitize-entity-names))
line-metadata {:timestamp (parse-log-timestamp timestamp options)
:line line}]
(if-let [matcher (->> regex-matchers
(filter #(re-matches (:regex %) sanitized-line))
(first))]
(let [regex-matches (rest (re-matches (:regex matcher) sanitized-line))
args-fn (or (:args matcher) (fn [& _]))
parsed-line (merge
line-metadata
(select-keys matcher [:logfmt :event :id])
(apply args-fn regex-matches))]
(process-parsed-line parsed-line log-owner-char-name))
line-metadata)))
(defn handle-line
[parsed-line data]
(handle-event parsed-line data))
(defn- active-encounter-processing
[parsed-line data]
(let [data (handle-line parsed-line data)]
(if-let [encounter-end (encounters/detect-encounter-end parsed-line data)]
(encounters/end-encounter parsed-line encounter-end data)
data)))
(defn- out-of-encounter-processing
[parsed-line data]
(if-let [encounter-name (encounters/detect-encounter-triggered parsed-line data)]
(->> data
(encounters/begin-encounter encounter-name parsed-line)
(handle-line parsed-line))
data))
(defn- parse-log*
[f options]
(with-open [rdr (io/reader f)]
(try
(reduce
(fn [data ^String line]
(try
(let [parsed (parse-line line options)]
(if (active-encounter? data)
(active-encounter-processing parsed data)
(out-of-encounter-processing parsed data)))
(catch Exception ex
(throw (ex-info "Parser error" {:line line} ex)))))
{:encounters []
:active-encounter nil}
(line-seq rdr))
(catch Exception ex
(flush)
(error ex "Parser error.")))))
(defn parse-log
[f options]
(let [line-ending-type (detect-file-line-ending-type f)]
(if-not line-ending-type
(warn "Could not detect line-ending type in log file. Assuming" :windows)
(info "Detected" line-ending-type "line-ending type in log file."))
(parse-log* f (merge
{:windows? (= :windows (or line-ending-type :windows))
:timezone (TimeZone/getDefault)
:year (current-year)}
options))))

View file

@ -0,0 +1,73 @@
(ns vwowrla.core.preparsing
(:import
(java.util Calendar GregorianCalendar TimeZone))
(:require
[clojure.string :as string]
[clojure.java.io :as io])
(:use
vwowrla.core.utils))
(def problem-entity-names (get-text-resource-as-lines "problem_entity_names.txt"))
(def problem-entity-name-to-fixed-name
(reduce
(fn [m problem-name]
(let [fixed-name (.replace problem-name "'s" "s")]
(-> m
(assoc-in [:problem-to-fixed problem-name] fixed-name)
(assoc-in [:fixed-to-problem fixed-name] problem-name))))
{:problem-to-fixed {}
:fixed-to-problem {}}
problem-entity-names))
(defn sanitize-entity-name
[^String entity-name]
(get-in problem-entity-name-to-fixed-name [:problem-to-fixed entity-name] entity-name))
(defn get-original-entity-name
[^String potentially-sanitized-entity-name]
(get-in problem-entity-name-to-fixed-name [:fixed-to-problem potentially-sanitized-entity-name] potentially-sanitized-entity-name))
(defn sanitize-entity-names
[^String line]
(reduce
(fn [^String line [^String problem-name ^String fixed-name]]
(.replace line problem-name fixed-name))
line
(:problem-to-fixed problem-entity-name-to-fixed-name)))
(defn undo-swstats-fixlogstring
[^String line]
(.replace line " 's" "'s"))
(defn parse-log-timestamp
[^String timestamp {:keys [^long year ^TimeZone timezone windows?] :as options}]
(if-let [matches (re-matches #"^(\d{1,2})\/(\d{1,2}) (\d{1,2}):(\d{2}):(\d{2})\.(\d{3})$" timestamp)]
(let [c (GregorianCalendar.)
[month day hour minute second millis] (rest matches)]
(.clear c)
(.setTimeZone c timezone)
(.set c year (if windows? (dec (->int month)) (->int month)) (->int day) (->int hour) (->int minute) (->int second))
(.set c Calendar/MILLISECOND (->int millis))
(.getTime c))))
(defn split-log-timestamp-and-content
[^String line]
(clojure.string/split line #" " 2))
(defn process-parsed-line
[{:keys [source-name target-name source] :as parsed-line} ^String log-owner-char-name]
(merge
parsed-line
(if source-name
{:source-name (if (= "you" (string/lower-case source-name))
log-owner-char-name
(get-original-entity-name source-name))})
(if target-name
{:target-name (if (= "you" (string/lower-case target-name))
log-owner-char-name
(get-original-entity-name target-name))})
(if source
{:source (if (= "you" (string/lower-case source))
log-owner-char-name
(get-original-entity-name source))})))

View file

@ -0,0 +1,75 @@
(ns vwowrla.core.utils
(:import
(java.io Reader)
(java.util Date))
(:require
[clojure.string :as string]
[clojure.edn :as edn]
[clojure.java.io :as io]
[cheshire.core :as json]))
(defn ->kw
[^String s]
(keyword (string/lower-case s)))
(defn ->int
[^String s]
(if s
(Integer/parseInt s)))
(defn one-of?
[x & more]
(boolean
(some #{x} more)))
(defn contained-in?
[x coll]
(boolean
(some #{x} coll)))
(defn detect-file-line-ending-type
[f]
(if-let [^Reader reader (io/reader f)]
(loop [ch (.read reader)]
(cond
(= -1 ch)
nil
(= 10 ch)
:linux
(= 13 ch)
(let [ch (.read reader)]
(if (= 10 ch)
:windows
:unix))
:default
(recur (.read reader))))))
(defn current-year
[]
(+ 1900 (.getYear (Date.))))
(defn time-between
[^Date a ^Date b]
(- (.getTime b)
(.getTime a)))
(defn get-text-resource-as-lines
[f]
(with-open [rdr (io/reader (io/resource f))]
(doall (line-seq rdr))))
(defn get-json-resource
[f]
(-> (io/resource f)
(io/reader)
(json/parse-stream true)))
(defn get-edn-resource
[f]
(-> (io/resource f)
(slurp)
(edn/read-string)))

View file

@ -0,0 +1,102 @@
(ns vwowrla.core.matchers.aura-gained-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest aura-buff-gained
(is (valid-matcher? (get-matcher regex-matchers :aura-buff-gained)))
(is (= (parse-line "5/25 21:21:16.385 Vasling gains Blink." options)
{:id :aura-buff-gained
:logfmt :aura-buff-gained
:event :aura-gained
:line "5/25 21:21:16.385 Vasling gains Blink."
:timestamp (parse-log-timestamp "5/25 21:21:16.385" options)
:target-name "Vasling"
:aura-name "Blink"
:type :buff
:stacks nil}))
(is (= (parse-line "5/25 21:16:27.257 Eggs gains Renew." options)
{:id :aura-buff-gained
:logfmt :aura-buff-gained
:event :aura-gained
:line "5/25 21:16:27.257 Eggs gains Renew."
:timestamp (parse-log-timestamp "5/25 21:16:27.257" options)
:target-name "Eggs"
:aura-name "Renew"
:type :buff
:stacks nil}))
(is (= (parse-line "5/25 23:26:03.093 Victore gains Bonereaver's Edge (2)." options)
{:id :aura-buff-gained
:logfmt :aura-buff-gained
:event :aura-gained
:line "5/25 23:26:03.093 Victore gains Bonereaver's Edge (2)."
:timestamp (parse-log-timestamp "5/25 23:26:03.093" options)
:target-name "Victore"
:aura-name "Bonereaver's Edge"
:type :buff
:stacks 2}))
(is (= (parse-line "5/25 21:42:59.537 You gain Regrowth." options)
{:id :aura-buff-gained
:logfmt :aura-buff-gained
:event :aura-gained
:line "5/25 21:42:59.537 You gain Regrowth."
:timestamp (parse-log-timestamp "5/25 21:42:59.537" options)
:target-name owner-char-name
:aura-name "Regrowth"
:type :buff
:stacks nil})))
(deftest aura-debuff-gained
(is (valid-matcher? (get-matcher regex-matchers :aura-debuff-gained)))
(is (= (parse-line "5/25 21:16:46.564 Vasling is afflicted by Gnomish Death Ray." options)
{:id :aura-debuff-gained
:logfmt :aura-debuff-gained
:event :aura-gained
:line "5/25 21:16:46.564 Vasling is afflicted by Gnomish Death Ray."
:timestamp (parse-log-timestamp "5/25 21:16:46.564" options)
:target-name "Vasling"
:aura-name "Gnomish Death Ray"
:type :debuff
:stacks nil}))
(is (= (parse-line "5/25 21:16:43.064 Onyxia is afflicted by Shadow Vulnerability (5)." options)
{:id :aura-debuff-gained
:logfmt :aura-debuff-gained
:event :aura-gained
:line "5/25 21:16:43.064 Onyxia is afflicted by Shadow Vulnerability (5)."
:timestamp (parse-log-timestamp "5/25 21:16:43.064" options)
:target-name "Onyxia"
:aura-name "Shadow Vulnerability"
:type :debuff
:stacks 5}))
(is (= (parse-line "5/25 21:43:05.511 You are afflicted by Weakened Soul." options)
{:id :aura-debuff-gained
:logfmt :aura-debuff-gained
:event :aura-gained
:line "5/25 21:43:05.511 You are afflicted by Weakened Soul."
:timestamp (parse-log-timestamp "5/25 21:43:05.511" options)
:target-name owner-char-name
:aura-name "Weakened Soul"
:type :debuff
:stacks nil})))

View file

@ -0,0 +1,90 @@
(ns vwowrla.core.matchers.aura-lost-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest aura-fades
(is (valid-matcher? (get-matcher regex-matchers :aura-fades)))
(is (= (parse-line "5/25 21:16:39.701 Defensive Stance fades from Eggs." options)
{:id :aura-fades
:logfmt :aura-fades
:event :aura-lost
:line "5/25 21:16:39.701 Defensive Stance fades from Eggs."
:timestamp (parse-log-timestamp "5/25 21:16:39.701" options)
:target-name "Eggs"
:aura-name "Defensive Stance"
:faded? true}))
(is (= (parse-line "5/25 21:17:53.550 Fire Shield fades from you." options)
{:id :aura-fades
:logfmt :aura-fades
:event :aura-lost
:line "5/25 21:17:53.550 Fire Shield fades from you."
:timestamp (parse-log-timestamp "5/25 21:17:53.550" options)
:target-name owner-char-name
:aura-name "Fire Shield"
:faded? true})))
(deftest aura-removed-self
(is (valid-matcher? (get-matcher regex-matchers :aura-removed-self)))
(is (= (parse-line "5/25 23:09:26.614 Your Winter's Chill is removed." options)
{:id :aura-removed-self
:logfmt :aura-removed
:event :aura-lost
:line "5/25 23:09:26.614 Your Winter's Chill is removed."
:timestamp (parse-log-timestamp "5/25 23:09:26.614" options)
:target-name owner-char-name
:aura-name "Winter's Chill"
:faded? false})))
(deftest aura-removed
(is (valid-matcher? (get-matcher regex-matchers :aura-removed)))
(is (= (parse-line "5/25 22:41:56.108 Magnomage's Shazzrah's Curse is removed." options)
{:id :aura-removed
:logfmt :aura-removed
:event :aura-lost
:line "5/25 22:41:56.108 Magnomage's Shazzrah's Curse is removed."
:timestamp (parse-log-timestamp "5/25 22:41:56.108" options)
:target-name "Magnomage"
:aura-name "Shazzrah's Curse"
:faded? false}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Twilight's Hammer Ambassador's Winter's Chill is removed." options)
{:id :aura-removed
:logfmt :aura-removed
:event :aura-lost
:line "1/2 3:45:00.123 Twilight's Hammer Ambassador's Winter's Chill is removed."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Twilight's Hammer Ambassador"
:aura-name "Winter's Chill"
:faded? false}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Twilight's Hammer Ambassador's Mana Shield is removed." options)
{:id :aura-removed
:logfmt :aura-removed
:event :aura-lost
:line "1/2 3:45:00.123 Twilight's Hammer Ambassador's Mana Shield is removed."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Twilight's Hammer Ambassador"
:aura-name "Mana Shield"
:faded? false})))

View file

@ -0,0 +1,96 @@
(ns vwowrla.core.matchers.cast-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest cast-begins
(is (valid-matcher? (get-matcher regex-matchers :cast-begins)))
(is (= (parse-line "5/25 23:27:34.377 Fei begins to cast Lesser Healing Wave." options)
{:id :cast-begins
:logfmt :cast-begins
:event :cast-begins
:line "5/25 23:27:34.377 Fei begins to cast Lesser Healing Wave."
:timestamp (parse-log-timestamp "5/25 23:27:34.377" options)
:source-name "Fei"
:skill "Lesser Healing Wave"
:spell? true}))
(is (= (parse-line "5/25 21:42:31.485 Bahamatt begins to perform Auto Shot." options)
{:id :cast-begins
:logfmt :cast-begins
:event :cast-begins
:line "5/25 21:42:31.485 Bahamatt begins to perform Auto Shot."
:timestamp (parse-log-timestamp "5/25 21:42:31.485" options)
:source-name "Bahamatt"
:skill "Auto Shot"
:spell? false}))
(is (= (parse-line "5/25 23:31:26.154 Laurent begins to perform Pick Lock." options)
{:id :cast-begins
:logfmt :cast-begins
:event :cast-begins
:line "5/25 23:31:26.154 Laurent begins to perform Pick Lock."
:timestamp (parse-log-timestamp "5/25 23:31:26.154" options)
:source-name "Laurent"
:skill "Pick Lock"
:spell? false}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You begin to perform Pick Lock." options)
{:id :cast-begins
:logfmt :cast-begins
:event :cast-begins
:line "1/2 3:45:00.123 You begin to perform Pick Lock."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:source-name owner-char-name
:skill "Pick Lock"
:spell? false})))
(deftest cast-instant
(is (valid-matcher? (get-matcher regex-matchers :cast)))
(is (= (parse-line "5/25 21:14:54.539 Eggs casts Place Unfired Blade." options)
{:id :cast
:logfmt :cast
:event :cast
:line "5/25 21:14:54.539 Eggs casts Place Unfired Blade."
:timestamp (parse-log-timestamp "5/25 21:14:54.539" options)
:source-name "Eggs"
:skill "Place Unfired Blade"
:spell? true}))
(is (= (parse-line "5/25 21:15:09.436 Pwnstar performs Berserking." options)
{:id :cast
:logfmt :cast
:event :cast
:line "5/25 21:15:09.436 Pwnstar performs Berserking."
:timestamp (parse-log-timestamp "5/25 21:15:09.436" options)
:source-name "Pwnstar"
:skill "Berserking"
:spell? false}))
(is (= (parse-line "5/25 21:46:25.894 You cast Remove Lesser Curse." options)
{:id :cast
:logfmt :cast
:event :cast
:line "5/25 21:46:25.894 You cast Remove Lesser Curse."
:timestamp (parse-log-timestamp "5/25 21:46:25.894" options)
:source-name owner-char-name
:skill "Remove Lesser Curse"
:spell? true})))

View file

@ -0,0 +1,56 @@
(ns vwowrla.core.matchers.damage-reflected-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest target-reflects-elemental-damage
(is (valid-matcher? (get-matcher regex-matchers :target-reflects-elemental-damage)))
(is (= (parse-line "5/25 21:13:30.482 Futilian reflects 16 Fire damage to Onyxia." options)
{:id :target-reflects-elemental-damage
:logfmt :target-reflects-elemental-damage
:event :damage-reflected
:line "5/25 21:13:30.482 Futilian reflects 16 Fire damage to Onyxia."
:timestamp (parse-log-timestamp "5/25 21:13:30.482" options)
:target-name "Onyxia"
:source-name "Futilian"
:damage 16
:damage-type :fire}))
(is (= (parse-line "5/25 23:26:09.552 Son of Flame reflects 50 Fire damage to Deadasfuk." options)
{:id :target-reflects-elemental-damage
:logfmt :target-reflects-elemental-damage
:event :damage-reflected
:line "5/25 23:26:09.552 Son of Flame reflects 50 Fire damage to Deadasfuk."
:timestamp (parse-log-timestamp "5/25 23:26:09.552" options)
:target-name "Deadasfuk"
:source-name "Son of Flame"
:damage 50
:damage-type :fire}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You reflect 42 Fire damage to Winna's Kitten." options)
{:id :target-reflects-elemental-damage
:logfmt :target-reflects-elemental-damage
:event :damage-reflected
:line "1/2 3:45:00.123 You reflect 42 Fire damage to Winna's Kitten."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Winna's Kitten"
:source-name owner-char-name
:damage 42
:damage-type :fire})))

View file

@ -0,0 +1,38 @@
(ns vwowrla.core.matchers.death-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest death
(is (valid-matcher? (get-matcher regex-matchers :death)))
(is (= (parse-line "5/25 21:17:18.944 Onyxia dies." options)
{:id :death
:logfmt :death
:event :death
:line "5/25 21:17:18.944 Onyxia dies."
:timestamp (parse-log-timestamp "5/25 21:17:18.944" options)
:source-name "Onyxia"}))
(is (= (parse-line "5/25 22:24:54.829 You die." options)
{:id :death
:logfmt :death
:event :death
:line "5/25 22:24:54.829 You die."
:timestamp (parse-log-timestamp "5/25 22:24:54.829" options)
:source-name owner-char-name})))

View file

@ -0,0 +1,97 @@
(ns vwowrla.core.matchers.dot-damages-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest dot-damages-target
(is (valid-matcher? (get-matcher regex-matchers :dot-damages-target)))
(is (= (parse-line "5/25 21:16:56.786 Onyxia suffers 261 Shadow damage from Smooth's Corruption." options)
{:id :dot-damages-target
:logfmt :dot-damages-target
:event :dot-damages-target
:line "5/25 21:16:56.786 Onyxia suffers 261 Shadow damage from Smooth's Corruption."
:timestamp (parse-log-timestamp "5/25 21:16:56.786" options)
:target-name "Onyxia"
:source-name "Smooth"
:skill "Corruption"
:damage 261
:damage-type :shadow
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 22:01:54.974 You suffer 1010 Fire damage from Gehennas's Rain of Fire. (60 absorbed)" options)
{:id :dot-damages-target
:logfmt :dot-damages-target
:event :dot-damages-target
:line "5/25 22:01:54.974 You suffer 1010 Fire damage from Gehennas's Rain of Fire. (60 absorbed)"
:timestamp (parse-log-timestamp "5/25 22:01:54.974" options)
:target-name owner-char-name
:source-name "Gehennas"
:skill "Rain of Fire"
:damage 1010
:damage-type :fire
:absorbed 60
:resisted nil}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia suffers 1337 Shadow damage from Sri'skulk's Arugal's Curse." options)
{:id :dot-damages-target
:logfmt :dot-damages-target
:event :dot-damages-target
:line "1/2 3:45:00.123 Onyxia suffers 1337 Shadow damage from Sri'skulk's Arugal's Curse."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Onyxia"
:source-name "Sri'skulk"
:skill "Arugal's Curse"
:damage 1337
:damage-type :shadow
:absorbed nil
:resisted nil}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia suffers 1337 Shadow damage from Sri'skulk's Corruption." options)
{:id :dot-damages-target
:logfmt :dot-damages-target
:event :dot-damages-target
:line "1/2 3:45:00.123 Onyxia suffers 1337 Shadow damage from Sri'skulk's Corruption."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Onyxia"
:source-name "Sri'skulk"
:skill "Corruption"
:damage 1337
:damage-type :shadow
:absorbed nil
:resisted nil})))
(deftest dot-damages-target-self
(is (valid-matcher? (get-matcher regex-matchers :dot-damages-target-self)))
(is (= (parse-line "5/25 21:15:18.909 Onyxian Whelp suffers 179 Frost damage from your Blizzard." options)
{:id :dot-damages-target-self
:logfmt :dot-damages-target
:event :dot-damages-target
:line "5/25 21:15:18.909 Onyxian Whelp suffers 179 Frost damage from your Blizzard."
:timestamp (parse-log-timestamp "5/25 21:15:18.909" options)
:target-name "Onyxian Whelp"
:source-name owner-char-name
:skill "Blizzard"
:damage 179
:damage-type :frost
:absorbed nil
:resisted nil})))

View file

@ -0,0 +1,13 @@
(ns vwowrla.core.matchers.matchers-test-utils)
(defn get-matcher [matchers id]
(->> matchers
(filter #(= (:id %) id))
(first)))
(defn valid-matcher? [matcher]
(and (map? matcher)
(:regex matcher)
(:logfmt matcher)
(:event matcher)
(:args matcher)))

View file

@ -0,0 +1,124 @@
(ns vwowrla.core.matchers.melee-avoided-by-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest melee-full-absorb
(is (valid-matcher? (get-matcher regex-matchers :melee-full-absorb)))
(is (= (parse-line "5/25 21:51:35.315 Magmadar attacks. Eggs absorbs all the damage." options)
{:id :melee-full-absorb
:logfmt :melee-full-absorb
:event :melee-avoided-by-target
:line "5/25 21:51:35.315 Magmadar attacks. Eggs absorbs all the damage."
:timestamp (parse-log-timestamp "5/25 21:51:35.315" options)
:target-name "Eggs"
:source-name "Magmadar"
:avoidance-method :absorb})))
(deftest melee-full-resist
(is (valid-matcher? (get-matcher regex-matchers :melee-full-resist)))
(is (= (parse-line "5/25 22:33:14.279 Baron Geddon attacks. Futilian resists all the damage." options)
{:id :melee-full-resist
:logfmt :melee-full-resist
:event :melee-avoided-by-target
:line "5/25 22:33:14.279 Baron Geddon attacks. Futilian resists all the damage."
:timestamp (parse-log-timestamp "5/25 22:33:14.279" options)
:target-name "Futilian"
:source-name "Baron Geddon"
:avoidance-method :resist})))
(deftest melee-miss
(is (valid-matcher? (get-matcher regex-matchers :melee-miss)))
(is (= (parse-line "5/25 23:27:21.695 Architrex misses Ragnaros." options)
{:id :melee-miss
:logfmt :melee-miss
:event :melee-avoided-by-target
:line "5/25 23:27:21.695 Architrex misses Ragnaros."
:timestamp (parse-log-timestamp "5/25 23:27:21.695" options)
:target-name "Ragnaros"
:source-name "Architrex"
:avoidance-method :miss})))
(deftest melee-parry
(is (valid-matcher? (get-matcher regex-matchers :melee-parry)))
(is (= (parse-line "5/25 23:07:34.127 Flamewaker Elite attacks. Boompow parries." options)
{:id :melee-parry
:logfmt :melee-parry
:event :melee-avoided-by-target
:line "5/25 23:07:34.127 Flamewaker Elite attacks. Boompow parries."
:timestamp (parse-log-timestamp "5/25 23:07:34.127" options)
:target-name "Boompow"
:source-name "Flamewaker Elite"
:avoidance-method :parry})))
(deftest melee-dodge
(is (valid-matcher? (get-matcher regex-matchers :melee-dodge)))
(is (= (parse-line "5/25 23:03:44.619 Laurent attacks. Ancient Core Hound dodges." options)
{:id :melee-dodge
:logfmt :melee-dodge
:event :melee-avoided-by-target
:line "5/25 23:03:44.619 Laurent attacks. Ancient Core Hound dodges."
:timestamp (parse-log-timestamp "5/25 23:03:44.619" options)
:target-name "Ancient Core Hound"
:source-name "Laurent"
:avoidance-method :dodge})))
(deftest melee-block
(is (valid-matcher? (get-matcher regex-matchers :melee-block)))
(is (= (parse-line "5/25 22:10:51.639 Molten Destroyer attacks. Futilian blocks." options)
{:id :melee-block
:logfmt :melee-block
:event :melee-avoided-by-target
:line "5/25 22:10:51.639 Molten Destroyer attacks. Futilian blocks."
:timestamp (parse-log-timestamp "5/25 22:10:51.639" options)
:target-name "Futilian"
:source-name "Molten Destroyer"
:avoidance-method :block})))
(deftest melee-evade
(is (valid-matcher? (get-matcher regex-matchers :melee-evade)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You attack. Onyxia evades." options)
{:id :melee-evade
:logfmt :melee-evade
:event :melee-avoided-by-target
:line "1/2 3:45:00.123 You attack. Onyxia evades."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Onyxia"
:source-name owner-char-name
:avoidance-method :evade})))
(deftest melee-immune
(is (valid-matcher? (get-matcher regex-matchers :melee-immune)))
(is (= (parse-line "5/25 22:38:40.210 Agusto attacks but Lava Elemental is immune." options)
{:id :melee-immune
:logfmt :melee-immune
:event :melee-avoided-by-target
:line "5/25 22:38:40.210 Agusto attacks but Lava Elemental is immune."
:timestamp (parse-log-timestamp "5/25 22:38:40.210" options)
:target-name "Lava Elemental"
:source-name "Agusto"
:avoidance-method :immune})))

View file

@ -0,0 +1,303 @@
(ns vwowrla.core.matchers.melee-damage-to-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest melee-damages-target
(is (valid-matcher? (get-matcher regex-matchers :melee-damages-target)))
(is (= (parse-line "5/25 21:42:23.038 Eggs hits Lava Surger for 175." options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "5/25 21:42:23.038 Eggs hits Lava Surger for 175."
:timestamp (parse-log-timestamp "5/25 21:42:23.038" options)
:target-name "Lava Surger"
:source-name "Eggs"
:damage 175
:hit-type nil
:crit? false
:absorbed nil
:blocked nil}))
(is (= (parse-line "6/16 21:29:44.927 You hit Lava Annihilator for 187." options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "6/16 21:29:44.927 You hit Lava Annihilator for 187."
:timestamp (parse-log-timestamp "6/16 21:29:44.927" options)
:target-name "Lava Annihilator"
:source-name owner-char-name
:damage 187
:hit-type nil
:crit? false
:absorbed nil
:blocked nil}))
(is (= (parse-line "5/25 21:42:22.322 Lava Surger crits Futilian for 1382." options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "5/25 21:42:22.322 Lava Surger crits Futilian for 1382."
:timestamp (parse-log-timestamp "5/25 21:42:22.322" options)
:target-name "Futilian"
:source-name "Lava Surger"
:damage 1382
:hit-type nil
:crit? true
:absorbed nil
:blocked nil}))
(is (= (parse-line "5/25 21:42:24.924 Lava Surger hits Eggs for 752. (81 blocked)" options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "5/25 21:42:24.924 Lava Surger hits Eggs for 752. (81 blocked)"
:timestamp (parse-log-timestamp "5/25 21:42:24.924" options)
:target-name "Eggs"
:source-name "Lava Surger"
:damage 752
:hit-type nil
:crit? false
:absorbed nil
:blocked 81}))
(is (= (parse-line "5/25 21:42:26.578 Laurent hits Lava Surger for 114. (glancing)" options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "5/25 21:42:26.578 Laurent hits Lava Surger for 114. (glancing)"
:timestamp (parse-log-timestamp "5/25 21:42:26.578" options)
:target-name "Lava Surger"
:source-name "Laurent"
:damage 114
:hit-type :glancing
:crit? false
:absorbed nil
:blocked nil}))
(is (= (parse-line "5/25 21:45:32.294 Lucifron hits Mightystroon for 1365. (crushing)" options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "5/25 21:45:32.294 Lucifron hits Mightystroon for 1365. (crushing)"
:timestamp (parse-log-timestamp "5/25 21:45:32.294" options)
:target-name "Mightystroon"
:source-name "Lucifron"
:damage 1365
:hit-type :crushing
:crit? false
:absorbed nil
:blocked nil}))
(is (= (parse-line "5/25 21:56:56.337 Flame Imp hits Aesthetera for 147. (395 absorbed)" options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "5/25 21:56:56.337 Flame Imp hits Aesthetera for 147. (395 absorbed)"
:timestamp (parse-log-timestamp "5/25 21:56:56.337" options)
:target-name "Aesthetera"
:source-name "Flame Imp"
:damage 147
:hit-type nil
:crit? false
:absorbed 395
:blocked nil}))
(is (= (parse-line "5/25 21:52:56.175 Magmadar hits Eggs for 160. (82 blocked) (607 absorbed)" options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "5/25 21:52:56.175 Magmadar hits Eggs for 160. (82 blocked) (607 absorbed)"
:timestamp (parse-log-timestamp "5/25 21:52:56.175" options)
:target-name "Eggs"
:source-name "Magmadar"
:damage 160
:hit-type nil
:crit? false
:absorbed 607
:blocked 82}))
(is (= (parse-line "6/9 21:50:40.122 Gehennas hits Mightystroon for 1530. (crushing) (96 absorbed)" options)
{:id :melee-damages-target
:logfmt :melee-damages-target
:event :melee-damage-to-target
:line "6/9 21:50:40.122 Gehennas hits Mightystroon for 1530. (crushing) (96 absorbed)"
:timestamp (parse-log-timestamp "6/9 21:50:40.122" options)
:target-name "Mightystroon"
:source-name "Gehennas"
:damage 1530
:hit-type :crushing
:crit? false
:absorbed 96
:blocked nil})))
(deftest melee-damages-target-elemental
(is (valid-matcher? (get-matcher regex-matchers :melee-damages-target-elemental)))
(is (= (parse-line "5/25 21:58:30.162 Firelord hits Crayson for 792 Fire damage." options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 21:58:30.162 Firelord hits Crayson for 792 Fire damage."
:timestamp (parse-log-timestamp "5/25 21:58:30.162" options)
:target-name "Crayson"
:source-name "Firelord"
:damage 792
:damage-type :fire
:hit-type nil
:crit? false
:absorbed nil
:resisted nil}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Twilight's Hammer Ambassador hits you for 42 Fire damage." options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "1/2 3:45:00.123 Twilight's Hammer Ambassador hits you for 42 Fire damage."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Twilight's Hammer Ambassador"
:damage 42
:damage-type :fire
:hit-type nil
:crit? false
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 22:03:50.816 Lava Spawn crits Strength of Earth Totem IV for 1172 Fire damage." options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 22:03:50.816 Lava Spawn crits Strength of Earth Totem IV for 1172 Fire damage."
:timestamp (parse-log-timestamp "5/25 22:03:50.816" options)
:target-name "Strength of Earth Totem IV"
:source-name "Lava Spawn"
:damage 1172
:damage-type :fire
:hit-type nil
:crit? true
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 21:58:42.215 Firelord hits Eggs for 480 Fire damage. (160 resisted)" options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 21:58:42.215 Firelord hits Eggs for 480 Fire damage. (160 resisted)"
:timestamp (parse-log-timestamp "5/25 21:58:42.215" options)
:target-name "Eggs"
:source-name "Firelord"
:damage 480
:damage-type :fire
:hit-type nil
:crit? false
:absorbed nil
:resisted 160}))
(is (= (parse-line "5/25 22:24:22.577 Baron Geddon hits Soma for 1592 Fire damage. (967 absorbed)" options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 22:24:22.577 Baron Geddon hits Soma for 1592 Fire damage. (967 absorbed)"
:timestamp (parse-log-timestamp "5/25 22:24:22.577" options)
:target-name "Soma"
:source-name "Baron Geddon"
:damage 1592
:damage-type :fire
:hit-type nil
:crit? false
:absorbed 967
:resisted nil}))
(is (= (parse-line "5/25 23:25:53.596 Son of Flame hits Agusto for 269 Fire damage. (135 resisted) (138 absorbed)" options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 23:25:53.596 Son of Flame hits Agusto for 269 Fire damage. (135 resisted) (138 absorbed)"
:timestamp (parse-log-timestamp "5/25 23:25:53.596" options)
:target-name "Agusto"
:source-name "Son of Flame"
:damage 269
:damage-type :fire
:hit-type nil
:crit? false
:absorbed 138
:resisted 135}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Baron Geddon hits Rrahg for 3609 Fire damage. (glancing)" options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "1/2 3:45:00.123 Baron Geddon hits Rrahg for 3609 Fire damage. (glancing)"
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Rrahg"
:source-name "Baron Geddon"
:damage 3609
:damage-type :fire
:hit-type :glancing
:crit? false
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 22:24:09.229 Baron Geddon hits Rrahg for 3609 Fire damage. (crushing)" options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 22:24:09.229 Baron Geddon hits Rrahg for 3609 Fire damage. (crushing)"
:timestamp (parse-log-timestamp "5/25 22:24:09.229" options)
:target-name "Rrahg"
:source-name "Baron Geddon"
:damage 3609
:damage-type :fire
:hit-type :crushing
:crit? false
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 22:24:11.225 Baron Geddon hits Hsaru for 2911 Fire damage. (crushing) (646 resisted)" options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 22:24:11.225 Baron Geddon hits Hsaru for 2911 Fire damage. (crushing) (646 resisted)"
:timestamp (parse-log-timestamp "5/25 22:24:11.225" options)
:target-name "Hsaru"
:source-name "Baron Geddon"
:damage 2911
:damage-type :fire
:hit-type :crushing
:crit? false
:absorbed nil
:resisted 646}))
(is (= (parse-line "5/25 22:33:22.440 Baron Geddon hits Futilian for 1509 Fire damage. (crushing) (1376 resisted) (371 absorbed)" options)
{:id :melee-damages-target-elemental
:logfmt :melee-damages-target-elemental
:event :melee-damage-to-target
:line "5/25 22:33:22.440 Baron Geddon hits Futilian for 1509 Fire damage. (crushing) (1376 resisted) (371 absorbed)"
:timestamp (parse-log-timestamp "5/25 22:33:22.440" options)
:target-name "Futilian"
:source-name "Baron Geddon"
:damage 1509
:damage-type :fire
:hit-type :crushing
:crit? false
:absorbed 371
:resisted 1376})))

View file

@ -0,0 +1,126 @@
(ns vwowrla.core.matchers.other-damage-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest environmental-damage
(is (valid-matcher? (get-matcher regex-matchers :environmental-damage)))
(is (= (parse-line "5/25 23:08:30.798 Hsaru suffers 713 points of fire damage." options)
{:id :environmental-damage
:logfmt :environmental-damage
:event :other-damage
:line "5/25 23:08:30.798 Hsaru suffers 713 points of fire damage."
:timestamp (parse-log-timestamp "5/25 23:08:30.798" options)
:target-name "Hsaru"
:damage 713
:damage-type :fire
:absorbed nil
:resisted nil}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You suffer 42 points of fire damage." options)
{:id :environmental-damage
:logfmt :environmental-damage
:event :other-damage
:line "1/2 3:45:00.123 You suffer 42 points of fire damage."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:damage 42
:damage-type :fire
:absorbed nil
:resisted nil})))
(deftest lava-swim-damage
(is (valid-matcher? (get-matcher regex-matchers :lava-swim-damage)))
(is (= (parse-line "5/25 21:58:13.460 Agusto loses 583 health for swimming in lava." options)
{:id :lava-swim-damage
:logfmt :lava-swim-damage
:event :other-damage
:line "5/25 21:58:13.460 Agusto loses 583 health for swimming in lava."
:timestamp (parse-log-timestamp "5/25 21:58:13.460" options)
:target-name "Agusto"
:source "Swimming in lava"
:damage 583
:damage-type :fire
:absorbed nil
:resisted nil}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You lose 42 health for swimming in lava." options)
{:id :lava-swim-damage
:logfmt :lava-swim-damage
:event :other-damage
:line "1/2 3:45:00.123 You lose 42 health for swimming in lava."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source "Swimming in lava"
:damage 42
:damage-type :fire
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 23:16:47.108 Agusto loses 0 health for swimming in lava. (632 absorbed)" options)
{:id :lava-swim-damage
:logfmt :lava-swim-damage
:event :other-damage
:line "5/25 23:16:47.108 Agusto loses 0 health for swimming in lava. (632 absorbed)"
:timestamp (parse-log-timestamp "5/25 23:16:47.108" options)
:target-name "Agusto"
:source "Swimming in lava"
:damage 0
:damage-type :fire
:absorbed 632
:resisted nil}))
(is (= (parse-line "6/9 21:32:31.616 Hsaru loses 205 health for swimming in lava. (380 absorbed)" options)
{:id :lava-swim-damage
:logfmt :lava-swim-damage
:event :other-damage
:line "6/9 21:32:31.616 Hsaru loses 205 health for swimming in lava. (380 absorbed)"
:timestamp (parse-log-timestamp "6/9 21:32:31.616" options)
:target-name "Hsaru"
:source "Swimming in lava"
:damage 205
:damage-type :fire
:absorbed 380
:resisted nil})))
(deftest fall-damage
(is (valid-matcher? (get-matcher regex-matchers :fall-damage)))
(is (= (parse-line "5/25 23:11:05.498 Crowquill falls and loses 167 health." options)
{:id :fall-damage
:logfmt :fall-damage
:event :other-damage
:line "5/25 23:11:05.498 Crowquill falls and loses 167 health."
:timestamp (parse-log-timestamp "5/25 23:11:05.498" options)
:target-name "Crowquill"
:source "Falling"
:damage 167}))
(is (= (parse-line "5/25 23:10:40.994 You fall and lose 939 health." options)
{:id :fall-damage
:logfmt :fall-damage
:event :other-damage
:line "5/25 23:10:40.994 You fall and lose 939 health."
:timestamp (parse-log-timestamp "5/25 23:10:40.994" options)
:target-name owner-char-name
:source "Falling"
:damage 939})))

View file

@ -0,0 +1,299 @@
(ns vwowrla.core.matchers.resource-gained-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest resource-gained-from-skill
(is (valid-matcher? (get-matcher regex-matchers :resource-gained-from-skill)))
(is (= (parse-line "5/25 21:21:32.915 Pwnstar gains 8 Mana from Pwnstar's Mana Regeneration." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "5/25 21:21:32.915 Pwnstar gains 8 Mana from Pwnstar's Mana Regeneration."
:timestamp (parse-log-timestamp "5/25 21:21:32.915" options)
:target-name "Pwnstar"
:source-name "Pwnstar"
:skill "Mana Regeneration"
:amount 8
:resource-type :mana}))
(is (= (parse-line "5/25 21:46:01.660 Vasling gains 375 Mana from Vasling's Replenish Mana." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "5/25 21:46:01.660 Vasling gains 375 Mana from Vasling's Replenish Mana."
:timestamp (parse-log-timestamp "5/25 21:46:01.660" options)
:target-name "Vasling"
:source-name "Vasling"
:skill "Replenish Mana"
:amount 375
:resource-type :mana}))
(is (= (parse-line "5/25 21:16:53.591 Architrex gains 25 Energy from Architrex's Relentless Strikes Effect." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "5/25 21:16:53.591 Architrex gains 25 Energy from Architrex's Relentless Strikes Effect."
:timestamp (parse-log-timestamp "5/25 21:16:53.591" options)
:target-name "Architrex"
:source-name "Architrex"
:skill "Relentless Strikes Effect"
:amount 25
:resource-type :energy}))
(is (= (parse-line "5/25 21:16:46.844 Boompow gains 1 Rage from Boompow's Bloodrage." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "5/25 21:16:46.844 Boompow gains 1 Rage from Boompow's Bloodrage."
:timestamp (parse-log-timestamp "5/25 21:16:46.844" options)
:target-name "Boompow"
:source-name "Boompow"
:skill "Bloodrage"
:amount 1
:resource-type :rage}))
(is (= (parse-line "5/25 21:13:17.531 Futilian gains 330 health from Leaf's Rejuvenation." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "5/25 21:13:17.531 Futilian gains 330 health from Leaf's Rejuvenation."
:timestamp (parse-log-timestamp "5/25 21:13:17.531" options)
:target-name "Futilian"
:source-name "Leaf"
:skill "Rejuvenation"
:amount 330
:resource-type :health}))
(is (= (parse-line "5/25 21:21:16.303 Shivaara gains 35 Happiness from Pwnstar's Feed Pet Effect." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "5/25 21:21:16.303 Shivaara gains 35 Happiness from Pwnstar's Feed Pet Effect."
:timestamp (parse-log-timestamp "5/25 21:21:16.303" options)
:target-name "Shivaara"
:source-name "Pwnstar"
:skill "Feed Pet Effect"
:amount 35
:resource-type :happiness}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Somebody gains 100 health from Somebody's Druid's Potion." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 Somebody gains 100 health from Somebody's Druid's Potion."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Somebody"
:source-name "Somebody"
:skill "Druid's Potion"
:amount 100
:resource-type :health}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Chok'sul gains 100 health from Chok'sul's Druid's Potion." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 Chok'sul gains 100 health from Chok'sul's Druid's Potion."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Chok'sul"
:source-name "Chok'sul"
:skill "Druid's Potion"
:amount 100
:resource-type :health}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gain 100 health from Somebody's Rejuvenation." options)
{:id :resource-gained-from-skill
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 You gain 100 health from Somebody's Rejuvenation."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Somebody"
:skill "Rejuvenation"
:amount 100
:resource-type :health})))
(deftest resource-gained-from-skill-self
(is (valid-matcher? (get-matcher regex-matchers :resource-gained-from-skill-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Futilian gains 1337 health from your Rejuvenation." options)
{:id :resource-gained-from-skill-self
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 Futilian gains 1337 health from your Rejuvenation."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Futilian"
:source-name owner-char-name
:skill "Rejuvenation"
:amount 1337
:resource-type :health}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gain 1 Rage from your Bloodrage." options)
{:id :resource-gained-from-skill-self
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 You gain 1 Rage from your Bloodrage."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Bloodrage"
:amount 1
:resource-type :rage}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gain 25 Energy from your Relentless Strikes Effect." options)
{:id :resource-gained-from-skill-self
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 You gain 25 Energy from your Relentless Strikes Effect."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Relentless Strikes Effect"
:amount 25
:resource-type :energy}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gain 1000 Mana from your Replenish Mana." options)
{:id :resource-gained-from-skill-self
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 You gain 1000 Mana from your Replenish Mana."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Replenish Mana"
:amount 1000
:resource-type :mana}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 SomePet gains 35 Happiness from your Feed Pet Effect." options)
{:id :resource-gained-from-skill-self
:logfmt :resource-gained-from-skill
:event :resource-gained
:line "1/2 3:45:00.123 SomePet gains 35 Happiness from your Feed Pet Effect."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "SomePet"
:source-name owner-char-name
:skill "Feed Pet Effect"
:amount 35
:resource-type :happiness})))
(deftest resource-gained
(is (valid-matcher? (get-matcher regex-matchers :resource-gained)))
(is (= (parse-line "5/25 22:15:35.674 You gain 1144 Mana from Replenish Mana." options)
{:id :resource-gained
:logfmt :resource-gained
:event :resource-gained
:line "5/25 22:15:35.674 You gain 1144 Mana from Replenish Mana."
:timestamp (parse-log-timestamp "5/25 22:15:35.674" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Replenish Mana"
:amount 1144
:resource-type :mana}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gain 1000 health from Rejuvenation." options)
{:id :resource-gained
:logfmt :resource-gained
:event :resource-gained
:line "1/2 3:45:00.123 You gain 1000 health from Rejuvenation."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Rejuvenation"
:amount 1000
:resource-type :health}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gain 1 Rage from Bloodrage." options)
{:id :resource-gained
:logfmt :resource-gained
:event :resource-gained
:line "1/2 3:45:00.123 You gain 1 Rage from Bloodrage."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Bloodrage"
:amount 1
:resource-type :rage}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gain 25 Energy from Relentless Strikes Effect." options)
{:id :resource-gained
:logfmt :resource-gained
:event :resource-gained
:line "1/2 3:45:00.123 You gain 25 Energy from Relentless Strikes Effect."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Relentless Strikes Effect"
:amount 25
:resource-type :energy})))
(deftest resource-drained-from-skill
(is (valid-matcher? (get-matcher regex-matchers :resource-drained-from-skill)))
(is (= (parse-line "6/16 22:36:47.916 Lazyspawn's Flee drains 225 Mana from Lazyspawn." options)
{:id :resource-drained-from-skill
:logfmt :resource-drained-from-skill
:event :resource-lost
:line "6/16 22:36:47.916 Lazyspawn's Flee drains 225 Mana from Lazyspawn."
:timestamp (parse-log-timestamp "6/16 22:36:47.916" options)
:target-name "Lazyspawn"
:source-name "Lazyspawn"
:skill "Flee"
:amount 225
:resource-type :mana}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Dreka'Sur's Unit Test's Curse drains 100 health from Greatfather Winter's Helper." options)
{:id :resource-drained-from-skill
:logfmt :resource-drained-from-skill
:event :resource-lost
:line "1/2 3:45:00.123 Dreka'Sur's Unit Test's Curse drains 100 health from Greatfather Winter's Helper."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Greatfather Winter's Helper"
:source-name "Dreka'Sur"
:skill "Unit Test's Curse"
:amount 100
:resource-type :health})))
(deftest resource-drained-from-skill-self
(is (valid-matcher? (get-matcher regex-matchers :resource-drained-from-skill-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Flee drains 225 Mana from you." options)
{:id :resource-drained-from-skill-self
:logfmt :resource-drained-from-skill
:event :resource-lost
:line "1/2 3:45:00.123 Your Flee drains 225 Mana from you."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Flee"
:amount 225
:resource-type :mana})))

View file

@ -0,0 +1,659 @@
(ns vwowrla.core.matchers.skill-avoided-by-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest skill-miss-self
(is (valid-matcher? (get-matcher regex-matchers :skill-miss-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Sunder Armor missed Firelord." options)
{:id :skill-miss-self
:logfmt :skill-miss
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Your Sunder Armor missed Firelord."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Firelord"
:source-name owner-char-name
:skill "Sunder Armor"
:avoidance-method :miss})))
(deftest skill-miss
(is (valid-matcher? (get-matcher regex-matchers :skill-miss)))
(is (= (parse-line "5/25 23:04:08.426 Eggs's Sunder Armor missed Firelord." options)
{:id :skill-miss
:logfmt :skill-miss
:event :skill-avoided-by-target
:line "5/25 23:04:08.426 Eggs's Sunder Armor missed Firelord."
:timestamp (parse-log-timestamp "5/25 23:04:08.426" options)
:target-name "Firelord"
:source-name "Eggs"
:skill "Sunder Armor"
:avoidance-method :miss}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack misses you." options)
{:id :skill-miss
:logfmt :skill-miss
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack misses you."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :miss}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack misses you." options)
{:id :skill-miss
:logfmt :skill-miss
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack misses you."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :miss})))
(deftest skill-parry-self
(is (valid-matcher? (get-matcher regex-matchers :skill-parry-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Test Attack was parried by Firelord." options)
{:id :skill-parry-self
:logfmt :skill-parry
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Your Test Attack was parried by Firelord."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Firelord"
:source-name owner-char-name
:skill "Test Attack"
:avoidance-method :parry})))
(deftest skill-parry
(is (valid-matcher? (get-matcher regex-matchers :skill-parry)))
(is (= (parse-line "5/25 23:02:30.319 Futilian's Heroic Strike was parried by Golemagg the Incinerator." options)
{:id :skill-parry
:logfmt :skill-parry
:event :skill-avoided-by-target
:line "5/25 23:02:30.319 Futilian's Heroic Strike was parried by Golemagg the Incinerator."
:timestamp (parse-log-timestamp "5/25 23:02:30.319" options)
:target-name "Golemagg the Incinerator"
:source-name "Futilian"
:skill "Heroic Strike"
:avoidance-method :parry}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was parried by Tester." options)
{:id :skill-parry
:logfmt :skill-parry
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was parried by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :parry}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was parried by Tester." options)
{:id :skill-parry
:logfmt :skill-parry
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was parried by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :parry})))
(deftest skill-parry-implied-self
(is (valid-matcher? (get-matcher regex-matchers :skill-parry-implied-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was parried." options)
{:id :skill-parry-implied-self
:logfmt :skill-parry
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was parried."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :parry}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was parried." options)
{:id :skill-parry-implied-self
:logfmt :skill-parry
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was parried."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :parry})))
(deftest skill-block-self
(is (valid-matcher? (get-matcher regex-matchers :skill-block-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Test Attack was blocked by Firelord." options)
{:id :skill-block-self
:logfmt :skill-block
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Your Test Attack was blocked by Firelord."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Firelord"
:source-name owner-char-name
:skill "Test Attack"
:avoidance-method :block})))
(deftest skill-block
(is (valid-matcher? (get-matcher regex-matchers :skill-block)))
(is (= (parse-line "5/25 23:08:34.885 Boompow's Shield Bash was blocked by Flamewaker Healer." options)
{:id :skill-block
:logfmt :skill-block
:event :skill-avoided-by-target
:line "5/25 23:08:34.885 Boompow's Shield Bash was blocked by Flamewaker Healer."
:timestamp (parse-log-timestamp "5/25 23:08:34.885" options)
:target-name "Flamewaker Healer"
:source-name "Boompow"
:skill "Shield Bash"
:avoidance-method :block}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was blocked by Tester." options)
{:id :skill-block
:logfmt :skill-block
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was blocked by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :block}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was blocked by Tester." options)
{:id :skill-block
:logfmt :skill-block
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was blocked by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :block})))
(deftest skill-dodge-self
(is (valid-matcher? (get-matcher regex-matchers :skill-dodge-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Test Attack was dodged by Firelord." options)
{:id :skill-dodge-self
:logfmt :skill-dodge
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Your Test Attack was dodged by Firelord."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Firelord"
:source-name owner-char-name
:skill "Test Attack"
:avoidance-method :dodge})))
(deftest skill-dodge
(is (valid-matcher? (get-matcher regex-matchers :skill-dodge)))
(is (= (parse-line "5/25 23:24:42.147 Victore's Mortal Strike was dodged by Ragnaros." options)
{:id :skill-dodge
:logfmt :skill-dodge
:event :skill-avoided-by-target
:line "5/25 23:24:42.147 Victore's Mortal Strike was dodged by Ragnaros."
:timestamp (parse-log-timestamp "5/25 23:24:42.147" options)
:target-name "Ragnaros"
:source-name "Victore"
:skill "Mortal Strike"
:avoidance-method :dodge}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was dodged by Tester." options)
{:id :skill-dodge
:logfmt :skill-dodge
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was dodged by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :dodge}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was dodged by Tester." options)
{:id :skill-dodge
:logfmt :skill-dodge
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was dodged by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :dodge})))
(deftest skill-dodge-implied-self
(is (valid-matcher? (get-matcher regex-matchers :skill-dodge-implied-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was dodged." options)
{:id :skill-dodge-implied-self
:logfmt :skill-dodge
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was dodged."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :dodge}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was dodged." options)
{:id :skill-dodge-implied-self
:logfmt :skill-dodge
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was dodged."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :dodge})))
(deftest skill-evade-self
(is (valid-matcher? (get-matcher regex-matchers :skill-evade-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Test Attack was evaded by Firelord." options)
{:id :skill-evade-self
:logfmt :skill-evade
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Your Test Attack was evaded by Firelord."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Firelord"
:source-name owner-char-name
:skill "Test Attack"
:avoidance-method :evade})))
(deftest skill-evade
(is (valid-matcher? (get-matcher regex-matchers :skill-evade)))
(is (= (parse-line "5/25 23:10:18.706 Futilian's Heroic Strike was evaded by Majordomo Executus." options)
{:id :skill-evade
:logfmt :skill-evade
:event :skill-avoided-by-target
:line "5/25 23:10:18.706 Futilian's Heroic Strike was evaded by Majordomo Executus."
:timestamp (parse-log-timestamp "5/25 23:10:18.706" options)
:target-name "Majordomo Executus"
:source-name "Futilian"
:skill "Heroic Strike"
:avoidance-method :evade}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was evaded by you." options)
{:id :skill-evade
:logfmt :skill-evade
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was evaded by you."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :evade}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was evaded by you." options)
{:id :skill-evade
:logfmt :skill-evade
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was evaded by you."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :evade})))
(deftest skill-resist-self
(is (valid-matcher? (get-matcher regex-matchers :skill-resist-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Firelord resists your Test Attack." options)
{:id :skill-resist-self
:logfmt :skill-resist
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Firelord resists your Test Attack."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Firelord"
:source-name owner-char-name
:skill "Test Attack"
:avoidance-method :resist})))
(deftest skill-resist
(is (valid-matcher? (get-matcher regex-matchers :skill-resist)))
(is (= (parse-line "6/9 21:37:10.291 Vamp resists Acal's Sap." options)
{:id :skill-resist
:logfmt :skill-resist
:event :skill-avoided-by-target
:line "6/9 21:37:10.291 Vamp resists Acal's Sap."
:timestamp (parse-log-timestamp "6/9 21:37:10.291" options)
:target-name "Vamp"
:source-name "Acal"
:skill "Sap"
:avoidance-method :resist}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard resists Umi's Mechanical Yeti's Unit Test's Attack." options)
{:id :skill-resist
:logfmt :skill-resist
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard resists Umi's Mechanical Yeti's Unit Test's Attack."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Onyxia's Elite Guard"
:source-name "Umi's Mechanical Yeti"
:skill "Unit Test's Attack"
:avoidance-method :resist}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard resists Umi's Mechanical Yeti's Test Attack." options)
{:id :skill-resist
:logfmt :skill-resist
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard resists Umi's Mechanical Yeti's Test Attack."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Onyxia's Elite Guard"
:source-name "Umi's Mechanical Yeti"
:skill "Test Attack"
:avoidance-method :resist})))
(deftest skill-absorb
(is (valid-matcher? (get-matcher regex-matchers :skill-absorb)))
(is (= (parse-line "5/25 21:15:43.435 Onyxia's Eruption is absorbed by Leaf." options)
{:id :skill-absorb
:logfmt :skill-absorb
:event :skill-avoided-by-target
:line "5/25 21:15:43.435 Onyxia's Eruption is absorbed by Leaf."
:timestamp (parse-log-timestamp "5/25 21:15:43.435" options)
:target-name "Leaf"
:source-name "Onyxia"
:skill "Eruption"
:avoidance-method :absorb}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack is absorbed by Tester." options)
{:id :skill-absorb
:logfmt :skill-absorb
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack is absorbed by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :absorb}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack is absorbed by Tester." options)
{:id :skill-absorb
:logfmt :skill-absorb
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack is absorbed by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :absorb})))
(deftest skill-absorb-self
(is (valid-matcher? (get-matcher regex-matchers :skill-absorb-self)))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Test Attack is absorbed by Firelord." options)
{:id :skill-absorb-self
:logfmt :skill-absorb
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Your Test Attack is absorbed by Firelord."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Firelord"
:source-name owner-char-name
:skill "Test Attack"
:avoidance-method :absorb})))
(deftest skill-absorb-2
(is (valid-matcher? (get-matcher regex-matchers :skill-absorb-2)))
(is (= (parse-line "5/25 21:43:08.285 You absorb Flame Imp's Fire Nova." options)
{:id :skill-absorb-2
:logfmt :skill-absorb-2
:event :skill-avoided-by-target
:line "5/25 21:43:08.285 You absorb Flame Imp's Fire Nova."
:timestamp (parse-log-timestamp "5/25 21:43:08.285" options)
:target-name owner-char-name
:source-name "Flame Imp"
:skill "Fire Nova"
:avoidance-method :absorb}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Umi's Mechanical Yeti absorbs Onyxia's Elite Guard's Unit Test's Attack." options)
{:id :skill-absorb-2
:logfmt :skill-absorb-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Umi's Mechanical Yeti absorbs Onyxia's Elite Guard's Unit Test's Attack."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Umi's Mechanical Yeti"
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :absorb}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Umi's Mechanical Yeti absorbs Onyxia's Elite Guard's Test Attack." options)
{:id :skill-absorb-2
:logfmt :skill-absorb-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Umi's Mechanical Yeti absorbs Onyxia's Elite Guard's Test Attack."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Umi's Mechanical Yeti"
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :absorb}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You absorb Onyxia's Elite Guard's Test Attack." options)
{:id :skill-absorb-2
:logfmt :skill-absorb-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 You absorb Onyxia's Elite Guard's Test Attack."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :absorb}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You absorb Onyxia's Elite Guard's Unit Test's Attack." options)
{:id :skill-absorb-2
:logfmt :skill-absorb-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 You absorb Onyxia's Elite Guard's Unit Test's Attack."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :absorb})))
(deftest skill-resist-2
(is (valid-matcher? (get-matcher regex-matchers :skill-resist-2)))
(is (= (parse-line "5/25 21:16:31.690 Ruktuku's Mind Flay was resisted by Onyxia." options)
{:id :skill-resist-2
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "5/25 21:16:31.690 Ruktuku's Mind Flay was resisted by Onyxia."
:timestamp (parse-log-timestamp "5/25 21:16:31.690" options)
:target-name "Onyxia"
:source-name "Ruktuku"
:skill "Mind Flay"
:avoidance-method :resist}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was resisted by Tester." options)
{:id :skill-resist-2
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Unit Test's Attack was resisted by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Unit Test's Attack"
:avoidance-method :resist}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was resisted by Tester." options)
{:id :skill-resist-2
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Attack was resisted by Tester."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Tester"
:source-name "Onyxia's Elite Guard"
:skill "Test Attack"
:avoidance-method :resist})))
(deftest skill-resist-2-self
(is (valid-matcher? (get-matcher regex-matchers :skill-resist-2-self)))
(is (= (parse-line "5/25 21:14:15.457 Your Frostbolt was resisted by Onyxia." options)
{:id :skill-resist-2-self
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "5/25 21:14:15.457 Your Frostbolt was resisted by Onyxia."
:timestamp (parse-log-timestamp "5/25 21:14:15.457" options)
:target-name "Onyxia"
:source-name owner-char-name
:skill "Frostbolt"
:avoidance-method :resist})))
(deftest skill-resist-no-source
(is (valid-matcher? (get-matcher regex-matchers :skill-resist-implied-self)))
(is (= (parse-line "5/25 22:40:54.804 Shazzrah's Shazzrah's Curse was resisted." options)
{:id :skill-resist-implied-self
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "5/25 22:40:54.804 Shazzrah's Shazzrah's Curse was resisted."
:timestamp (parse-log-timestamp "5/25 22:40:54.804" options)
:target-name owner-char-name
:source-name "Shazzrah"
:skill "Shazzrah's Curse"
:avoidance-method :resist}))
(is (= (parse-line "5/25 23:08:26.297 Flamewaker Healer's Shadow Shock was resisted." options)
{:id :skill-resist-implied-self
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "5/25 23:08:26.297 Flamewaker Healer's Shadow Shock was resisted."
:timestamp (parse-log-timestamp "5/25 23:08:26.297" options)
:target-name owner-char-name
:source-name "Flamewaker Healer"
:skill "Shadow Shock"
:avoidance-method :resist}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Tester's Curse was resisted." options)
{:id :skill-resist-implied-self
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Tester's Curse was resisted."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Tester's Curse"
:avoidance-method :resist}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Curse was resisted." options)
{:id :skill-resist-implied-self
:logfmt :skill-resist-2
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Curse was resisted."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Onyxia's Elite Guard"
:skill "Test Curse"
:avoidance-method :resist})))
(deftest skill-immune-self
(is (valid-matcher? (get-matcher regex-matchers :skill-immune-self)))
(is (= (parse-line "5/25 22:02:47.619 Your Fire Blast failed. Gehennas is immune." options)
{:id :skill-immune-self
:logfmt :skill-immune
:event :skill-avoided-by-target
:line "5/25 22:02:47.619 Your Fire Blast failed. Gehennas is immune."
:timestamp (parse-log-timestamp "5/25 22:02:47.619" options)
:target-name "Gehennas"
:source-name owner-char-name
:skill "Fire Blast"
:avoidance-method :immune})))
(deftest skill-immune
(is (valid-matcher? (get-matcher regex-matchers :skill-immune)))
(is (= (parse-line "5/25 21:16:35.991 Onyxia's Bellowing Roar fails. Slater is immune." options)
{:id :skill-immune
:logfmt :skill-immune
:event :skill-avoided-by-target
:line "5/25 21:16:35.991 Onyxia's Bellowing Roar fails. Slater is immune."
:timestamp (parse-log-timestamp "5/25 21:16:35.991" options)
:target-name "Slater"
:source-name "Onyxia"
:skill "Bellowing Roar"
:avoidance-method :immune}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Tester's Curse fails. Slater is immune." options)
{:id :skill-immune
:logfmt :skill-immune
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Tester's Curse fails. Slater is immune."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Slater"
:source-name "Onyxia's Elite Guard"
:skill "Tester's Curse"
:avoidance-method :immune}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Curse fails. Slater is immune." options)
{:id :skill-immune
:logfmt :skill-immune
:event :skill-avoided-by-target
:line "1/2 3:45:00.123 Onyxia's Elite Guard's Test Curse fails. Slater is immune."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Slater"
:source-name "Onyxia's Elite Guard"
:skill "Test Curse"
:avoidance-method :immune})))

View file

@ -0,0 +1,235 @@
(ns vwowrla.core.matchers.skill-damage-to-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest skill-damages-target-elemental-self
(is (valid-matcher? (get-matcher regex-matchers :skill-damages-target-elemental-self)))
(is (= (parse-line "5/25 21:42:29.230 Your Frostbolt hits Lava Surger for 881 Frost damage." options)
{:id :skill-damages-target-elemental-self
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:42:29.230 Your Frostbolt hits Lava Surger for 881 Frost damage."
:timestamp (parse-log-timestamp "5/25 21:42:29.230" options)
:source-name owner-char-name
:target-name "Lava Surger"
:skill "Frostbolt"
:damage 881
:damage-type :frost
:crit? false
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 21:45:50.850 Your Frostbolt crits Flamewaker Protector for 1784 Frost damage." options)
{:id :skill-damages-target-elemental-self
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:45:50.850 Your Frostbolt crits Flamewaker Protector for 1784 Frost damage."
:timestamp (parse-log-timestamp "5/25 21:45:50.850" options)
:source-name owner-char-name
:target-name "Flamewaker Protector"
:skill "Frostbolt"
:damage 1784
:damage-type :frost
:crit? true
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 21:46:03.864 Your Fire Blast hits Flamewaker Protector for 503 Fire damage. (167 resisted)" options)
{:id :skill-damages-target-elemental-self
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:46:03.864 Your Fire Blast hits Flamewaker Protector for 503 Fire damage. (167 resisted)"
:timestamp (parse-log-timestamp "5/25 21:46:03.864" options)
:source-name owner-char-name
:target-name "Flamewaker Protector"
:skill "Fire Blast"
:damage 503
:damage-type :fire
:crit? false
:absorbed nil
:resisted 167})))
(deftest skill-damages-target-self
(is (valid-matcher? (get-matcher regex-matchers :skill-damages-target-self)))
; TODO
)
(deftest skill-damages-target-short-self
(is (valid-matcher? (get-matcher regex-matchers :skill-damages-target-short-self)))
; TODO
)
(deftest skill-damages-target-elemental
(is (valid-matcher? (get-matcher regex-matchers :skill-damages-target-elemental)))
(is (= (parse-line "5/25 21:42:31.082 Tomaka's Shadow Bolt hits Lava Surger for 1119 Shadow damage." options)
{:id :skill-damages-target-elemental
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:42:31.082 Tomaka's Shadow Bolt hits Lava Surger for 1119 Shadow damage."
:timestamp (parse-log-timestamp "5/25 21:42:31.082" options)
:source-name "Tomaka"
:target-name "Lava Surger"
:skill "Shadow Bolt"
:damage 1119
:damage-type :shadow
:crit? false
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 21:42:33.583 Fervens's Frostbolt crits Lava Surger for 1825 Frost damage." options)
{:id :skill-damages-target-elemental
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:42:33.583 Fervens's Frostbolt crits Lava Surger for 1825 Frost damage."
:timestamp (parse-log-timestamp "5/25 21:42:33.583" options)
:source-name "Fervens"
:target-name "Lava Surger"
:skill "Frostbolt"
:damage 1825
:damage-type :frost
:crit? true
:absorbed nil
:resisted nil}))
(is (= (parse-line "5/25 21:42:42.644 Magnomage's Fire Blast hits Lava Surger for 171 Fire damage. (513 resisted)" options)
{:id :skill-damages-target-elemental
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:42:42.644 Magnomage's Fire Blast hits Lava Surger for 171 Fire damage. (513 resisted)"
:timestamp (parse-log-timestamp "5/25 21:42:42.644" options)
:source-name "Magnomage"
:target-name "Lava Surger"
:skill "Fire Blast"
:damage 171
:damage-type :fire
:crit? false
:absorbed nil
:resisted 513}))
(is (= (parse-line "5/25 21:51:35.316 Magmadar's Magma Spit hits Eggs for 3 Fire damage. (91 absorbed)" options)
{:id :skill-damages-target-elemental
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:51:35.316 Magmadar's Magma Spit hits Eggs for 3 Fire damage. (91 absorbed)"
:timestamp (parse-log-timestamp "5/25 21:51:35.316" options)
:source-name "Magmadar"
:target-name "Eggs"
:skill "Magma Spit"
:damage 3
:damage-type :fire
:crit? false
:absorbed 91
:resisted nil}))
(is (= (parse-line "5/25 21:56:49.465 Flame Imp's Fire Nova hits you for 89 Fire damage. (409 resisted) (320 absorbed)" options)
{:id :skill-damages-target-elemental
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 21:56:49.465 Flame Imp's Fire Nova hits you for 89 Fire damage. (409 resisted) (320 absorbed)"
:timestamp (parse-log-timestamp "5/25 21:56:49.465" options)
:source-name "Flame Imp"
:target-name owner-char-name
:skill "Fire Nova"
:damage 89
:damage-type :fire
:crit? false
:absorbed 320
:resisted 409}))
(is (= (parse-line "5/25 22:21:33.172 Firewalker's Fire Blossom hits Ruktuku for 1430 Fire damage. (798 resisted) (964 absorbed)" options)
{:id :skill-damages-target-elemental
:logfmt :skill-damages-target-elemental
:event :skill-damage-to-target
:line "5/25 22:21:33.172 Firewalker's Fire Blossom hits Ruktuku for 1430 Fire damage. (798 resisted) (964 absorbed)"
:timestamp (parse-log-timestamp "5/25 22:21:33.172" options)
:source-name "Firewalker"
:target-name "Ruktuku"
:skill "Fire Blossom"
:damage 1430
:damage-type :fire
:crit? false
:absorbed 964
:resisted 798})))
; TODO: might not need this one... see comments for the associated matcher
(deftest skill-damages-target
(is (valid-matcher? (get-matcher regex-matchers :skill-damages-target)))
; TODO
)
(deftest skill-damages-target-short
(is (valid-matcher? (get-matcher regex-matchers :skill-damages-target-short)))
(is (= (parse-line "5/25 21:42:27.247 Peasemold's Ambush crits Lava Surger for 1398." options)
{:id :skill-damages-target-short
:logfmt :skill-damages-target-short
:event :skill-damage-to-target
:line "5/25 21:42:27.247 Peasemold's Ambush crits Lava Surger for 1398."
:timestamp (parse-log-timestamp "5/25 21:42:27.247" options)
:source-name "Peasemold"
:target-name "Lava Surger"
:skill "Ambush"
:damage 1398
:crit? true
:absorbed nil
:blocked nil}))
(is (= (parse-line "5/25 21:42:28.379 Eggs's Shield Slam hits Lava Surger for 240." options)
{:id :skill-damages-target-short
:logfmt :skill-damages-target-short
:event :skill-damage-to-target
:line "5/25 21:42:28.379 Eggs's Shield Slam hits Lava Surger for 240."
:timestamp (parse-log-timestamp "5/25 21:42:28.379" options)
:source-name "Eggs"
:target-name "Lava Surger"
:skill "Shield Slam"
:damage 240
:crit? false
:absorbed nil
:blocked nil}))
(is (= (parse-line "5/25 21:42:32.488 Victore's Whirlwind crits Lava Surger for 902. (31 blocked)" options)
{:id :skill-damages-target-short
:logfmt :skill-damages-target-short
:event :skill-damage-to-target
:line "5/25 21:42:32.488 Victore's Whirlwind crits Lava Surger for 902. (31 blocked)"
:timestamp (parse-log-timestamp "5/25 21:42:32.488" options)
:source-name "Victore"
:target-name "Lava Surger"
:skill "Whirlwind"
:damage 902
:crit? true
:absorbed nil
:blocked 31}))
(is (= (parse-line "6/9 22:31:18.633 Golemagg the Incinerator's Earthquake hits Architrex for 1034. (460 absorbed)" options)
{:id :skill-damages-target-short
:logfmt :skill-damages-target-short
:event :skill-damage-to-target
:line "6/9 22:31:18.633 Golemagg the Incinerator's Earthquake hits Architrex for 1034. (460 absorbed)"
:timestamp (parse-log-timestamp "6/9 22:31:18.633" options)
:source-name "Golemagg the Incinerator"
:target-name "Architrex"
:skill "Earthquake"
:damage 1034
:crit? false
:absorbed 460
:blocked nil})))

View file

@ -0,0 +1,100 @@
(ns vwowrla.core.matchers.skill-heals-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest skill-heals-target-self
(is (valid-matcher? (get-matcher regex-matchers :skill-heals-target-self)))
(is (= (parse-line "6/9 22:16:35.330 Your Healing Potion heals you for 1627." options)
{:id :skill-heals-target-self
:logfmt :skill-heals-target
:event :skill-heals-target
:line "6/9 22:16:35.330 Your Healing Potion heals you for 1627."
:timestamp (parse-log-timestamp "6/9 22:16:35.330" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Healing Potion"
:amount 1627
:crit? false}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Your Healing Touch critically heals you for 3000." options)
{:id :skill-heals-target-self
:logfmt :skill-heals-target
:event :skill-heals-target
:line "1/2 3:45:00.123 Your Healing Touch critically heals you for 3000."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name owner-char-name
:skill "Healing Touch"
:amount 3000
:crit? true})))
(deftest skill-heals-target
(is (valid-matcher? (get-matcher regex-matchers :skill-heals-target)))
(is (= (parse-line "5/25 21:16:40.096 Fei's Lesser Healing Wave heals Futilian for 1012." options)
{:id :skill-heals-target
:logfmt :skill-heals-target
:event :skill-heals-target
:line "5/25 21:16:40.096 Fei's Lesser Healing Wave heals Futilian for 1012."
:timestamp (parse-log-timestamp "5/25 21:16:40.096" options)
:target-name "Futilian"
:source-name "Fei"
:skill "Lesser Healing Wave"
:amount 1012
:crit? false}))
(is (= (parse-line "5/25 21:16:40.686 Leaf's Regrowth critically heals Futilian for 1885." options)
{:id :skill-heals-target
:logfmt :skill-heals-target
:event :skill-heals-target
:line "5/25 21:16:40.686 Leaf's Regrowth critically heals Futilian for 1885."
:timestamp (parse-log-timestamp "5/25 21:16:40.686" options)
:target-name "Futilian"
:source-name "Leaf"
:skill "Regrowth"
:amount 1885
:crit? true}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Ribbly's Crony's Unit Tester's Heal heals you for 2000." options)
{:id :skill-heals-target
:logfmt :skill-heals-target
:event :skill-heals-target
:line "1/2 3:45:00.123 Ribbly's Crony's Unit Tester's Heal heals you for 2000."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source-name "Ribbly's Crony"
:skill "Unit Tester's Heal"
:amount 2000
:crit? false}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Ribbly's Crony's Test Heal critically heals Futilian for 3000." options)
{:id :skill-heals-target
:logfmt :skill-heals-target
:event :skill-heals-target
:line "1/2 3:45:00.123 Ribbly's Crony's Test Heal critically heals Futilian for 3000."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Futilian"
:source-name "Ribbly's Crony"
:skill "Test Heal"
:amount 3000
:crit? true})))

View file

@ -0,0 +1,89 @@
(ns vwowrla.core.matchers.skill-interrupted-by-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest skill-interrupt
(is (valid-matcher? (get-matcher regex-matchers :skill-interrupt)))
(is (= (parse-line "5/25 22:42:15.079 Shazzrah interrupts Oprawindfury's Lesser Healing Wave." options)
{:id :skill-interrupt
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:line "5/25 22:42:15.079 Shazzrah interrupts Oprawindfury's Lesser Healing Wave."
:timestamp (parse-log-timestamp "5/25 22:42:15.079" options)
:target-name "Oprawindfury"
:source-name "Shazzrah"
:skill "Lesser Healing Wave"}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Warug's Target Dummy interrupts Jen'shan's Unit Tester's Heal." options)
{:id :skill-interrupt
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:line "1/2 3:45:00.123 Warug's Target Dummy interrupts Jen'shan's Unit Tester's Heal."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Jen'shan"
:source-name "Warug's Target Dummy"
:skill "Unit Tester's Heal"}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 Warug's Target Dummy interrupts Jen'shan's Test Heal." options)
{:id :skill-interrupt
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:line "1/2 3:45:00.123 Warug's Target Dummy interrupts Jen'shan's Test Heal."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Jen'shan"
:source-name "Warug's Target Dummy"
:skill "Test Heal"}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You interrupt Jen'shan's Unit Tester's Heal." options)
{:id :skill-interrupt
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:line "1/2 3:45:00.123 You interrupt Jen'shan's Unit Tester's Heal."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Jen'shan"
:source-name owner-char-name
:skill "Unit Tester's Heal"}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You interrupt Jen'shan's Test Heal." options)
{:id :skill-interrupt
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:line "1/2 3:45:00.123 You interrupt Jen'shan's Test Heal."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Jen'shan"
:source-name owner-char-name
:skill "Test Heal"})))
(deftest skill-interrupt-self
(is (valid-matcher? (get-matcher regex-matchers :skill-interrupt-self)))
(is (= (parse-line "6/9 22:16:52.007 Shazzrah interrupts your Frostbolt." options)
{:id :skill-interrupt-self
:logfmt :skill-interrupt
:event :skill-interrupted-by-target
:line "6/9 22:16:52.007 Shazzrah interrupts your Frostbolt."
:timestamp (parse-log-timestamp "6/9 22:16:52.007" options)
:target-name owner-char-name
:source-name "Shazzrah"
:skill "Frostbolt"})))

View file

@ -0,0 +1,79 @@
(ns vwowrla.core.matchers.skill-performed-on-target-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest skill-performed-on-target
(is (valid-matcher? (get-matcher regex-matchers :skill-performed-on-target)))
(is (= (parse-line "6/16 21:48:26.263 Acal performs Feint on Lava Surger." options)
{:id :skill-performed-on-target
:logfmt :skill-performed-on-target
:event :skill-performed-on-target
:line "6/16 21:48:26.263 Acal performs Feint on Lava Surger."
:timestamp (parse-log-timestamp "6/16 21:48:26.263" options)
:target-name "Lava Surger"
:source-name "Acal"
:skill "Feint"
:spell? false}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You perform Feint on Onyxia." options)
{:id :skill-performed-on-target
:logfmt :skill-performed-on-target
:event :skill-performed-on-target
:line "1/2 3:45:00.123 You perform Feint on Onyxia."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name "Onyxia"
:source-name owner-char-name
:skill "Feint"
:spell? false}))
(is (= (parse-line "5/25 22:27:13.538 Crayson casts Ancestral Spirit on Acal." options)
{:id :skill-performed-on-target
:logfmt :skill-performed-on-target
:event :skill-performed-on-target
:line "5/25 22:27:13.538 Crayson casts Ancestral Spirit on Acal."
:timestamp (parse-log-timestamp "5/25 22:27:13.538" options)
:skill "Ancestral Spirit"
:target-name "Acal"
:source-name "Crayson"
:spell? true}))
(is (= (parse-line "5/25 23:23:44.343 Acal casts Melt Weapon on Acal: Gutgore Ripper damaged." options)
{:id :skill-performed-on-target
:logfmt :skill-performed-on-target
:event :skill-performed-on-target
:line "5/25 23:23:44.343 Acal casts Melt Weapon on Acal: Gutgore Ripper damaged."
:timestamp (parse-log-timestamp "5/25 23:23:44.343" options)
:target-name "Acal"
:source-name "Acal"
:skill "Melt Weapon"
:spell? true
:extra "Gutgore Ripper damaged"}))
(is (= (parse-line "5/25 23:07:22.282 Aesthetera casts Polymorph: Pig on Flamewaker Healer." options)
{:id :skill-performed-on-target
:logfmt :skill-performed-on-target
:event :skill-performed-on-target
:line "5/25 23:07:22.282 Aesthetera casts Polymorph: Pig on Flamewaker Healer."
:timestamp (parse-log-timestamp "5/25 23:07:22.282" options)
:target-name "Flamewaker Healer"
:source-name "Aesthetera"
:skill "Polymorph: Pig"
:spell? true})))

View file

@ -0,0 +1,53 @@
(ns vwowrla.core.matchers.special-gained-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.matchers.matchers-test-utils)
(:require
[vwowrla.core.parser :refer [parse-line]]
[vwowrla.core.preparsing :refer [parse-log-timestamp]]
[vwowrla.core.matchers :refer [regex-matchers]]))
(def options {:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})
(def owner-char-name (:log-owner-char-name options))
(def year (:year options))
(def timezone (:timezone options))
(deftest special-gained
(is (valid-matcher? (get-matcher regex-matchers :special-gained)))
(is (= (parse-line "5/25 21:13:34.098 Futilian gains 2 extra attacks through Fury of Forgewright." options)
{:id :special-gained
:logfmt :special-gained
:event :special-gained
:line "5/25 21:13:34.098 Futilian gains 2 extra attacks through Fury of Forgewright."
:timestamp (parse-log-timestamp "5/25 21:13:34.098" options)
:target-name "Futilian"
:source "Fury of Forgewright"
:special "2 extra attacks"}))
(is (= (parse-line "5/25 21:16:16.199 Bigjuicy gains 1 extra attack through Hand of Justice." options)
{:id :special-gained
:logfmt :special-gained
:event :special-gained
:line "5/25 21:16:16.199 Bigjuicy gains 1 extra attack through Hand of Justice."
:timestamp (parse-log-timestamp "5/25 21:16:16.199" options)
:target-name "Bigjuicy"
:source "Hand of Justice"
:special "1 extra attack"}))
; NOTE: this combat log entry was not generated by the WoW client, it was hand-written for this test
(is (= (parse-line "1/2 3:45:00.123 You gains 1 extra attack through Sword Specialization." options)
{:id :special-gained
:logfmt :special-gained
:event :special-gained
:line "1/2 3:45:00.123 You gains 1 extra attack through Sword Specialization."
:timestamp (parse-log-timestamp "1/2 3:45:00.123" options)
:target-name owner-char-name
:source "Sword Specialization"
:special "1 extra attack"})))

View file

@ -0,0 +1,16 @@
(ns vwowrla.core.parser-test
(:import
(java.util TimeZone))
(:use
clojure.test
vwowrla.core.parser))
(deftest barebones-line-parse-results
(let [parsed (parse-line "1/2 3:45:00.000 Test combat log line with 2 spaces in content part."
{:log-owner-char-name "Blasticus"
:year 2015
:timezone (TimeZone/getDefault)
:windows? false})]
(is (and (map? parsed)
(contains? parsed :timestamp)
(contains? parsed :line)))))

View file

@ -0,0 +1,55 @@
(ns vwowrla.core.preparsing-test
(:import (java.util TimeZone))
(:use
clojure.test
vwowrla.core.preparsing))
(deftest entity-name-sanitizing
(is (= (sanitize-entity-name "Twilight's Hammer Ambassador")
"Twilights Hammer Ambassador"))
(is (= (sanitize-entity-name "Ragnaros")
"Ragnaros"))
(is (= (sanitize-entity-name "C'Thun")
"C'Thun")))
(deftest entity-name-unsanitizing
(is (= (get-original-entity-name "Twilights Hammer Ambassador")
"Twilight's Hammer Ambassador"))
(is (= (get-original-entity-name "Ragnaros")
"Ragnaros"))
(is (= (get-original-entity-name "C'Thun")
"C'Thun")))
(deftest combat-log-line-entity-name-sanitizing
(is (= (sanitize-entity-names "Twilight's Hammer Ambassador's Flame Shock hits you for 1234 Fire damage.")
"Twilights Hammer Ambassador's Flame Shock hits you for 1234 Fire damage."))
(is (= (sanitize-entity-names "Magnomage's Shazzrah's Curse is removed.")
"Magnomage's Shazzrah's Curse is removed.")))
(deftest combat-log-line-undo-swstats-fixlogstring
(is (= (undo-swstats-fixlogstring "Twilight's Hammer Ambassador 's Flame Shock hits you for 1234 Fire damage.")
"Twilight's Hammer Ambassador's Flame Shock hits you for 1234 Fire damage."))
(is (= (undo-swstats-fixlogstring "Magnomage 's Shazzrah's Curse is removed.")
"Magnomage's Shazzrah's Curse is removed.")))
(deftest date-parsing
(let [options {:year 2015
:timezone (TimeZone/getTimeZone "America/Toronto")
:windows? false}]
(is (= (parse-log-timestamp "6/9 21:36:18.227" options)
#inst "2015-07-10T01:36:18.227-00:00"))
(is (= (parse-log-timestamp "11/31 13:37:42.123" options)
#inst "2015-12-31T18:37:42.123-00:00"))
(is (= (parse-log-timestamp "0/1 00:00:00.000" options)
#inst "2015-01-01T05:00:00.000-00:00")))
(let [options {:year 2015
:timezone (TimeZone/getTimeZone "America/Toronto")
:windows? true}]
(is (= (parse-log-timestamp "7/24 10:25:50.444" options)
#inst "2015-07-24T14:25:50.444-00:00"))))
(deftest raw-log-line-splitting
(is (= (split-log-timestamp-and-content "6/9 22:50:49.199 Ragnaros dies.")
["6/9 22:50:49.199" "Ragnaros dies."]))
(is (= (split-log-timestamp-and-content "1/2 3:45:00.000 Test combat log line with 2 spaces in content part.")
["1/2 3:45:00.000" "Test combat log line with 2 spaces in content part."])))