evtc/
state_change.rs

1use num_enum::{FromPrimitive, IntoPrimitive};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "strum")]
7use strum::{Display, EnumCount, EnumIter, IntoStaticStr, VariantNames};
8
9/// Combat state change kinds.
10#[derive(
11    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, IntoPrimitive, FromPrimitive,
12)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14#[cfg_attr(
15    feature = "strum",
16    derive(Display, EnumCount, EnumIter, IntoStaticStr, VariantNames)
17)]
18#[repr(u8)]
19pub enum StateChange {
20    /// Not used, different kind of event.
21    None = 0,
22
23    /// Agent entered combat.
24    ///
25    /// `src_agent` entered combat.
26    /// `dst_agent` contains the subgroup.
27    /// `value` contains the Profession id.
28    /// `buff_dmg` contains the Elite Specialization id.
29    ///
30    /// EVTC: yes, limited to agent table outside instances.
31    ///
32    /// Realtime: yes, limited to squad.
33    EnterCombat = 1,
34
35    /// Agent left combat.
36    ///
37    /// `src_agent` left combat.
38    ///
39    /// EVTC: yes, limited to agent table outside instances.
40    ///
41    /// Realtime: yes, limited to squad.
42    ExitCombat = 2,
43
44    /// Agent is now alive.
45    ///
46    /// `src_agent` is alive.
47    ///
48    /// EVTC: yes, limited to agent table outside instances.
49    ///
50    /// Realtime: yes, limited to squad.
51    ChangeUp = 3,
52
53    /// Agent is now dead.
54    ///
55    /// `src_agent` is dead.
56    ///
57    /// EVTC: yes, limited to agent table outside instances.
58    ///
59    /// Realtime: yes, limited to squad.
60    ChangeDead = 4,
61
62    /// Agent is now downed.
63    ///
64    /// `src_agent` is down.
65    ///
66    /// EVTC: yes, limited to agent table outside instances.
67    ///
68    /// Realtime: yes, limited to squad.
69    ChangeDown = 5,
70
71    /// Agent is now in game tracking range.
72    ///
73    /// `src_agent` is now tracked.
74    ///
75    /// EVTC: yes, limited to agent table outside instances.
76    ///
77    /// Realtime: no
78    Spawn = 6,
79
80    /// Source agent is no longer being tracked or out of game tracking range.
81    ///
82    /// `src_agent` is no longer tracked.
83    ///
84    /// EVTC: yes, limited to agent table outside instances.
85    ///
86    /// Realtime: no
87    Despawn = 7,
88
89    /// Agent health change.
90    ///
91    /// `src_agent` health changed.
92    /// `dst_agent` contains percentage as `percent * 10000`.
93    /// For example 99.5% will be `9950`.
94    ///
95    /// EVTC: yes, limited to agent table outside instances.
96    ///
97    /// Realtime: no
98    HealthUpdate = 8,
99
100    /// Squad combat start, first player entered combat. Logging has started.
101    ///
102    /// `value` contains the server Unix timestamp as `u32`.
103    /// `buff_dmg` contains the local Unix timestamp.
104    ///
105    /// `src_agent` is `0x637261` (ArcDPS id) if log EVTC and species id if realtime API.
106    ///
107    /// EVTC: yes
108    ///
109    /// Realtime: yes
110    SquadCombatStart = 9,
111
112    /// Squad combat end, last player has left combat. Logging has ended.
113    ///
114    /// `value` contains the server Unix timestamp as `u32`.
115    /// `buff_dmg` contains the local Unix timestamp.
116    ///
117    /// `src_agent` is `0x637261` (ArcDPS id) if log EVTC and species id if realtime API.
118    ///
119    /// EVTC: yes
120    ///
121    /// Realtime: yes
122    SquadCombatEnd = 10,
123
124    /// Agent swapped weapon set.
125    ///
126    /// `src_agent` swapped weapons.
127    /// `dst_agent` contains the new weapon set id.
128    /// `value` contains the previous weapon set id.
129    ///
130    /// `0`/`1` for underwater weapon sets and `4`/`5` for land weapon sets.
131    /// `2` is bundle/kit weapon set and `3` transform weapon set.
132    ///
133    /// EVTC: yes
134    ///
135    /// Realtime: yes
136    WeaponSwap = 11,
137
138    /// Agent maximum health change.
139    ///
140    /// `src_agent` changed max health.
141    /// `dst_agent` contains the new maximum health.
142    ///
143    /// EVTC: yes, limited to non-players.
144    ///
145    /// Realtime: no
146    MaxHealthUpdate = 12,
147
148    /// Player recording the log.
149    ///
150    /// `src_agent` is point of view
151    ///
152    /// EVTC: yes
153    ///
154    /// Realtime: no
155    PointOfView = 13,
156
157    /// Game text language.
158    ///
159    /// `src_agent` contains the text language id.
160    ///
161    /// EVTC: yes
162    ///
163    /// Realtime: no
164    Language = 14,
165
166    /// Game build.
167    ///
168    /// `src_agent` contains the game build.
169    ///
170    /// EVTC: yes
171    ///
172    /// Realtime: no
173    GWBuild = 15,
174
175    /// Sever shard id.
176    ///
177    /// `src_agent` contains the shard id.
178    ///
179    /// EVTC: yes
180    ///
181    /// Realtime: no
182    ShardId = 16,
183
184    /// Source agent got a reward chest.
185    ///
186    /// `src_agent` is always self.
187    /// `dst_agent` contains the reward id.
188    /// `value` contains the reward type.
189    ///
190    /// EVTC: yes
191    ///
192    /// Realtime: yes
193    Reward = 17,
194
195    /// Initially present buffs.
196    ///
197    /// Identical to buff application event.
198    /// Appears once per buff per agent on logging start.
199    ///
200    /// EVTC: yes, limited to squad outside instances.
201    ///
202    /// Realtime: yes, limited to squad.
203    BuffInitial = 18,
204
205    /// Agent position change.
206    ///
207    /// `src_agent` changed position.
208    /// `dst_agent` contains XYZ coordinates as `[f32; 3]`.
209    ///
210    /// EVTC: yes, limited to agent table outside instances.
211    ///
212    /// Realtime: no
213    Position = 19,
214
215    /// Agent velocity change.
216    ///
217    /// `src_agent` changed position.
218    /// `dst_agent` contains XYZ velocity as `[f32; 3]`.
219    ///
220    /// EVTC: yes, limited to agent table outside instances.
221    ///
222    /// Realtime: no
223    Velocity = 20,
224
225    /// Agent facing change.
226    ///
227    /// `src_agent` changed position.
228    /// `dst_agent` contains XY direction as `[f32; 2]`.
229    ///
230    /// EVTC: yes, limited to agent table outside instances.
231    ///
232    /// Realtime: no
233    Facing = 21,
234
235    /// Agent team change.
236    ///
237    /// `src_agent` changed team.
238    /// `dst_agent` contains the new team id.
239    /// `value` contains the previous team id.
240    ///
241    /// EVTC: yes, limited to agent table outside instances.
242    ///
243    /// Realtime: yes, limited to squad.
244    TeamChange = 22,
245
246    /// Agent is an attack target of parent gadget.
247    ///
248    /// `src_agent` is the attack target.
249    /// `dst_agent` is the parent gadget.
250    /// `value` contains the current targetable state.
251    ///
252    /// EVTC: yes, limited to agent table outside instances.
253    ///
254    /// Realtime: no
255    AttackTarget = 23,
256
257    /// Agent changed targetable state.
258    ///
259    /// `src_agent` changed targetable state.
260    /// `dst_agent` contains the new targetable state.
261    /// `0` for no, `1` for yes. Default is yes.
262    ///
263    /// EVTC: yes, limited to agent table outside instances.
264    ///
265    /// Realtime: no
266    Targetable = 24,
267
268    /// Map id.
269    ///
270    /// `src_agent` contains the map id.
271    ///
272    /// EVTC: yes
273    ///
274    /// Realtime: no
275    MapId = 25,
276
277    /// Used internally by ArcDPS.
278    /// Should not appear anywhere.
279    ReplInfo = 26,
280
281    /// Buff stack is now active.
282    ///
283    /// `src_agent` has the buff.
284    /// `dst_agent` contains the buff stack id marked active.
285    /// `value` contains the current buff duration.
286    ///
287    /// EVTC: yes, limited to squad outside instances.
288    ///
289    /// Realtime: yes, limited to squad.
290    StackActive = 27,
291
292    /// Buff stack duration changed.
293    ///
294    /// `src_agent` has the buff.
295    /// `value` contains the new duration to reset to (also marks inactive).
296    /// `pad61-64` contains the stack id.
297    ///
298    /// EVTC: yes, limited to squad outside instances.
299    ///
300    /// Realtime: yes, limited to squad.
301    StackReset = 28,
302
303    /// Agent is in guild.
304    ///
305    /// `src_agent` is in guild.
306    /// `dst_agent` contains the guild guid as [u8; 16].
307    ///
308    /// Given in client form, needs minor rearrange for API form.
309    ///
310    /// EVTC: yes, limited to squad outside instances.
311    ///
312    /// Realtime: yes, limited to squad.
313    Guild = 29,
314
315    /// Buff information.
316    ///
317    /// `skill_id` is skilldef id of buff.
318    /// `is_offcycle` contains the category.
319    /// `pad61` contains the stacking type.
320    /// `src_master_instance_id` contains the max stacks.
321    /// `overstack_value` contains the duration cap.
322    ///
323    /// If `is_flanking` probably invulnerability-like.
324    /// If `is_shields` probably invert-like.
325    /// If `pad62` probably resistance-like.
326    ///
327    /// One event per buff.
328    ///
329    /// EVTC: yes
330    ///
331    /// Realtime: no
332    BuffInfo = 30,
333
334    /// Buff formula.
335    ///
336    /// `skill_id` is skilldef id of buff.
337    /// `time` contains `type`, `attr1`, `attr2`, `param1`, `param2`, `param3`, `trait_condition_src` and `trait_condition_self`, `content_reference` as `[f32; 9]`.
338    /// `src_instance_id` contains `buff_condition_src` and `buff_condition_self` as `[f32; 2]`.
339    ///
340    /// If `is_flanking` not NPC.
341    /// If `is_shields` not player.
342    /// If `is_offcycle` break.
343    ///
344    /// `overstack_value` is value of type determined by `pad61`.
345    ///
346    /// One event per buff formula.
347    ///
348    /// EVTC: yes
349    ///
350    /// Realtime: no
351    BuffFormula = 31,
352
353    /// Skill information.
354    ///
355    /// `skill_id` is skilldef id of ability.
356    /// `time` contains `recharge`, `range0`, `range1` and `tooltiptime` as `[f32; 4]`.
357    ///
358    /// One event per ability.
359    ///
360    /// EVTC: yes
361    ///
362    /// Realtime: no
363    SkillInfo = 32,
364
365    /// Skill action.
366    ///
367    /// `skill_id` is skilldef id of ability.
368    /// `src_agent` contains the action type.
369    /// `dst_agent` contains the time since activation in milliseconds.
370    ///
371    /// One event per ability timing.
372    ///
373    /// EVTC: yes
374    ///
375    /// Realtime: no
376    SkillTiming = 33,
377
378    /// Agent breakbar state change.
379    ///
380    /// `src_agent` changed breakbar state.
381    /// `value` contains the new breakbar state as [`u16`] (game enum: active, recover, immune, none).
382    ///
383    /// EVTC: yes, limited to agent table outside instances.
384    ///
385    /// Realtime: no
386    BreakbarState = 34,
387
388    /// Breakbar percentage.
389    ///
390    /// `src_agent` has breakbar percentage.
391    /// `value` contains percentage as [`f32`].
392    ///
393    /// EVTC: yes, limited to agent table outside instances.
394    ///
395    /// Realtime: no
396    BreakbarPercent = 35,
397
398    /// Message with log integrity information.
399    ///
400    /// `time` contains the message as a null-terminated C string.
401    ///
402    /// EVTC: yes
403    ///
404    /// Realtime: no
405    Integrity = 36,
406
407    /// Agent has a marker.
408    ///
409    /// `src_agent` has the marker.
410    /// `value` contains the markerdef id (volatile, depends on game build).
411    /// If `buff`, marker is a commander tag.
412    ///
413    /// A marker id of `0` indicates a remove.
414    ///
415    /// EVTC: yes, limited to agent table outside instances.
416    ///
417    /// Realtime: no
418    Marker = 37,
419
420    /// Agent barrier change.
421    ///
422    /// `src_agent` has barrier percentage.
423    /// `dst_agent` contains percentage as `percent * 10000`.
424    /// For example 99.5% will be `9950`.
425    ///
426    /// EVTC: yes, limited to agent table outside instances.
427    ///
428    /// Realtime: no
429    BarrierUpdate = 38,
430
431    /// Arc UI stats reset.
432    ///
433    /// `src_agent` contains the species id of the agent triggering the reset, for example boss species id.
434    ///
435    /// EVTC: yes
436    ///
437    /// Realtime: yes
438    StatReset = 39,
439
440    /// A custom event created by an extension (addon/plugin).
441    Extension = 40,
442
443    /// Delayed combat event.
444    ///
445    /// Event deemed "unsafe" for realtime that was held back until after squad left combat.
446    ///
447    /// EVTC: no
448    ///
449    /// Realtime: yes
450    ApiDelayed = 41,
451
452    /// Map instance start timestamp.
453    ///
454    /// `src_agent` contains the time in milliseconds since the instance was started.
455    ///
456    /// EVTC: yes
457    ///
458    /// Realtime: yes
459    InstanceStart = 42,
460
461    /// Tick rate health.
462    ///
463    /// `src_agent` is `25 - tickrate` when `tickrate < 21`.
464    /// Every 500ms.
465    ///
466    /// EVTC: yes
467    ///
468    /// Realtime: no
469    RateHealth = 43,
470
471    /// Retired since 230716.
472    ///
473    /// Previously: *Last 90% before down.*
474    ///
475    /// *`src_agent` is enemy agent that went down, `dst_agent` is time in ms since last 90%.
476    /// For downs contribution.*
477    Last90BeforeDown = 44,
478
479    /// Retired since 230716.
480    ///
481    /// Previously: *Effect created or ended.*
482    ///
483    /// *`skill_id` contains the effect id.*
484    /// *`src_agent` is the effect owner.*
485    /// *`dst_agent` if effect located at agent.*
486    /// *Otherwise `value` contains XYZ position as `[f32; 3]`, `affinity` contains XY orientation as `[f32; 2]`, `pad61` contains Z orientation as [`f32`].*
487    /// *`is_shields` contains duration as [`u16`].*
488    /// *If `is_flanking`, duration is a tracking id.*
489    /// *If effect id is `0`, effect ended and `is_shields` contains tracking id.*
490    Effect45 = 45,
491
492    /// Content id to GUID.
493    ///
494    /// `skill_id` is the content id.
495    /// `src_agent` contains the persistent content guid as `[u8; 16]`.
496    /// `overstack_value` contains a variant of [`ContentLocal`](crate::guid::ContentLocal).
497    ///
498    /// *Not used in realtime API.*
499    IdToGUID = 46,
500
501    /// Log boss agent changed.
502    ///
503    /// `src_agent` contains the species id of the agent.
504    /// `dst_agent` is the boss agent.
505    /// `value` contains the server Unix timestamp as `u32`.
506    /// `buff_dmg` contains the local Unix timestamp.
507    ///
508    /// EVTC: yes
509    ///
510    /// Realtime: yes
511    LogNPCUpdate = 47,
512
513    /// Used internally by ArcDPS.
514    /// Should not appear anywhere.
515    IdleEvent = 48,
516
517    /// A custom combat event created by an extension (addon/plugin).
518    ///
519    /// `skill_id` is treated as skill id and will be added to the EVTC skill table.
520    ExtensionCombat = 49,
521
522    /// Fractal scale.
523    ///
524    /// `src_agent` contains the scale.
525    ///
526    /// EVTC: yes
527    ///
528    /// Realtime: no
529    FractalScale = 50,
530
531    /// Visual effect created or ended.
532    ///
533    /// `skill_id` contains the effect id.
534    /// `src_agent` is the effect owner (if any).
535    /// `dst_agent` if effect located at agent.
536    /// Otherwise `value` contains XYZ location as `[f32; 3]`.
537    /// `affinity` contains duration as [`u32`].
538    /// `is_buffremove` contains trackable id as [`u32`].
539    /// `is_shields` contains orientation as `[i16; 3]`.
540    /// Orientation values are `original * 1000` or [`i16::MIN`]/[`i16::MAX`] if out of bounds.
541    ///
542    /// EVTC: yes, limited to agent table outside instances
543    ///
544    /// Realtime: no
545    Effect51 = 51,
546
547    /// Combat ruleset.
548    ///
549    /// `src_agent` has bit 0 set if PvE rules, bit 1 if WvW rules and bit 2 if PvP rules.
550    ///
551    /// EVTC: yes
552    ///
553    /// Realtime: no
554    Ruleset = 52,
555
556    /// Squad ground marker placed or removed.
557    ///
558    /// `src_agent` contains XYZ location as `[f32; 3]` or [`f32::INFINITY`] if removed.
559    /// `skill_id` contains the index of the squad marker, for example `0` for Arrow marker.
560    ///
561    /// EVTC: yes
562    ///
563    /// Realtime: no
564    SquadMarker = 53,
565
566    /// ArcDPS build information.
567    ///
568    /// `src_agent` contains ArcDPS build as null-terminated C string.
569    ///
570    /// EVTC: yes
571    ///
572    /// Realtime: no
573    ArcBuild = 54,
574
575    /// Agent gliding state change.
576    ///
577    /// `src_agent` changed gliding state.
578    /// `value` contains `1` if deployed and `0` if stowed.
579    ///
580    /// EVTC: yes, limited to agent table outside instances.
581    ///
582    /// Realtime: no
583    Glider = 55,
584
585    /// Disable stopped early.
586    ///
587    /// `src_agent` stopped the disable.
588    /// `value` contains duration remaining.
589    ///
590    /// EVTC: yes, limited to agent table outside instances
591    ///
592    /// Realtime: no
593    Stunbreak = 56,
594
595    /// Missile created.
596    ///
597    /// `src_agent` contains the source agent.
598    /// `value` contains the location x/y/z as `[i16; 3]` divided by 10.
599    /// `overstack_value` contains the skin id (player only).
600    /// `skill_id` contains the associated skill id.
601    /// `pad61` contains the trackable missile id as [`u32`].
602    ///
603    /// EVTC: yes, limited to agent table outside instances
604    ///
605    /// Realtime: no
606    MissileCreate = 57,
607
608    /// Missile launched or relaunched.
609    ///
610    /// `src_agent` contains the source agent.
611    /// `dst_agent` contains the target agent, if set and in range.
612    /// `value` contains the target x/y/z and current x/y/z as `[i16; 6]` divided by 10.
613    /// `skill_id` contains the associated skill id.
614    /// `affinity` contains the launch motion as [`u8`]. Unknown values, directly from client.
615    /// `result` contains the motion radius/range as [`i16`].
616    /// `is_buffremove` contains the launch flags as [`u32`]. Unknown values, directly from client.
617    /// `is_shields` contains the missile speed as [`i16`].
618    /// `pad61` contains the trackable missile id as [`u32`].
619    ///
620    /// EVTC: yes, limited to agent table outside instances
621    ///
622    /// Realtime: no
623    MissileLaunch = 58,
624
625    /// Missile removed or destroyed.
626    ///
627    /// `src_agent` contains the related agent.
628    /// `value` contains the total friendly fire damage.
629    /// `skill_id` contains the associated skill id.
630    /// `is_src_flanking` if at least one enemy was hit along the way.
631    /// `pad61` contains the trackable missile id as [`u32`].
632    ///
633    /// EVTC: yes, limited to agent table outside instances
634    ///
635    /// Realtime: no
636    MissileRemove = 59,
637
638    /// Ground effect created.
639    ///
640    /// `src_agent` contains the owner agent.
641    /// `dst_agent` contains the origin x/y/z divided by 10 and orient x/y/z multiplied by 1000 as `[i16; 6]`.
642    /// `skill_id` contains the volatile effect content id, map to stable GUID via [`StateChange::IdToGUID`] event.
643    /// `affinity` contains the effect duration as [`u32`]. If the duration is zero, it may be a fixed length duration (see [`StateChange::IdToGUID`] event).
644    /// `is_buffremove` contains the flags.
645    /// `is_flanking` if effect is located on a non-static platform.
646    /// `is_shields` contains the scale (if zero, assume 1) multiplied by 1000 as `i16`.
647    /// `pad61` contains the trackable effect id as [`u32`].
648    ///
649    /// EVTC: yes, limited to agent table outside instances
650    ///
651    /// Realtime: no
652    EffectGroundCreate = 60,
653
654    /// Ground effect removed.
655    ///
656    /// `pad61` contains the trackable effect id as [`u32`].
657    ///
658    /// EVTC: yes
659    ///
660    /// Realtime: no
661    EffectGroundRemove = 61,
662
663    /// Effect atttached to agent created.
664    ///
665    /// `src_agent` contains the related agent.
666    /// `skill_id` contains the volatile effect content id, map to stable GUID via [`StateChange::IdToGUID`] event.
667    /// `affinity` contains effect duration as [`u32`]. If the duration is zero, it may be a fixed length duration (see [`StateChange::IdToGUID`] event).
668    /// `pad61` contains the trackable effect id as [`u32`].
669    ///
670    /// EVTC: yes, limited to agent table outside instances
671    ///
672    /// Realtime: no
673    EffectAgentCreate = 62,
674
675    /// Effect attached to agent removed.
676    ///
677    /// `src_agent` contains the related agent.
678    /// `pad61` contains the trackable effect id as [`u32`].
679    ///
680    /// EVTC: yes, limited to agent table outside instances
681    ///
682    /// Realtime: no
683    EffectAgentRemove = 63,
684
685    /// Unknown or invalid.
686    #[num_enum(catch_all)]
687    Unknown(u8),
688}
689
690impl StateChange {
691    /// Checks whether the statechange has an associated timestamp.
692    #[inline]
693    pub fn has_time(&self) -> bool {
694        matches!(
695            self,
696            Self::None
697                | Self::EnterCombat
698                | Self::ExitCombat
699                | Self::ChangeUp
700                | Self::ChangeDead
701                | Self::ChangeDown
702                | Self::Spawn
703                | Self::Despawn
704                | Self::HealthUpdate
705                | Self::SquadCombatStart
706                | Self::SquadCombatEnd
707                | Self::WeaponSwap
708                | Self::MaxHealthUpdate
709                | Self::Reward
710                | Self::BuffInitial
711                | Self::Position
712                | Self::Velocity
713                | Self::Facing
714                | Self::TeamChange
715                | Self::AttackTarget
716                | Self::Targetable
717                | Self::StackActive
718                | Self::StackReset
719                | Self::BreakbarState
720                | Self::BreakbarPercent
721                | Self::BarrierUpdate
722                | Self::StatReset
723                | Self::Extension
724                | Self::ApiDelayed
725                | Self::Last90BeforeDown
726                | Self::Effect45
727                | Self::LogNPCUpdate
728                | Self::ExtensionCombat
729                | Self::Effect51
730                | Self::SquadMarker
731                | Self::Glider
732                | Self::Stunbreak
733                | Self::MissileCreate
734                | Self::MissileLaunch
735                | Self::MissileRemove
736                | Self::EffectGroundCreate
737                | Self::EffectGroundRemove
738                | Self::EffectAgentCreate
739                | Self::EffectAgentRemove
740        )
741    }
742}