Modifiers Guide¶
AI Summary
Track buffs, debuffs, and auras using parse_modifiers(). Each modifier entry includes parent entity, caster, ability handle, creation time, duration (-1 for permanent), stack count, and flags for aura/debuff. Use auras_only=True to filter aura effects. Modifiers track status effects like stuns, slows, and item buffs throughout the match. Combine with entity queries to resolve entity handles to names.
Overview¶
Modifiers represent buffs, debuffs, auras, and other status effects applied to units during the match.
from python_manta import MantaParser
parser = MantaParser()
result = parser.parse_modifiers("match.dem", max_modifiers=100)
for mod in result.modifiers:
duration_str = f"{mod.duration}s" if mod.duration >= 0 else "permanent"
print(f"[Tick {mod.tick}] Entity {mod.parent}: {duration_str}")
Basic Usage¶
All Modifiers¶
result = parser.parse_modifiers("match.dem", max_modifiers=500)
print(f"Total modifiers captured: {result.total_modifiers}")
for mod in result.modifiers:
mod_type = "DEBUFF" if mod.is_debuff else "BUFF"
aura_tag = " (AURA)" if mod.is_aura else ""
print(f"[{mod.tick}] {mod_type}{aura_tag} on entity {mod.parent}")
Auras Only¶
result = parser.parse_modifiers("match.dem", auras_only=True, max_modifiers=200)
print(f"Aura modifiers: {len(result.modifiers)}")
for mod in result.modifiers:
print(f"[{mod.tick}] Aura on entity {mod.parent}, stacks: {mod.stack_count}")
Modifier Entry Fields¶
Each ModifierEntry contains:
| Field | Type | Description |
|---|---|---|
tick |
int | Game tick when modifier was recorded |
net_tick |
int | Network tick |
parent |
int | Entity handle of unit with modifier |
caster |
int | Entity handle of caster |
ability |
int | Ability handle that created modifier |
modifier_class |
int | Modifier class ID |
serial_num |
int | Serial number for tracking |
index |
int | Modifier index |
creation_time |
float | Game time when created |
duration |
float | Duration in seconds (-1 = permanent) |
stack_count |
int | Number of stacks |
is_aura |
bool | Whether it's an aura |
is_debuff |
bool | Whether it's a debuff |
Common Use Cases¶
Duration Analysis¶
result = parser.parse_modifiers("match.dem", max_modifiers=500)
permanent = []
timed = []
for mod in result.modifiers:
if mod.duration < 0:
permanent.append(mod)
else:
timed.append(mod)
print(f"Permanent modifiers: {len(permanent)}")
print(f"Timed modifiers: {len(timed)}")
if timed:
durations = [m.duration for m in timed]
print(f"Duration range: {min(durations):.1f}s - {max(durations):.1f}s")
print(f"Average duration: {sum(durations)/len(durations):.1f}s")
Buff vs Debuff Count¶
result = parser.parse_modifiers("match.dem", max_modifiers=1000)
buffs = [m for m in result.modifiers if not m.is_debuff]
debuffs = [m for m in result.modifiers if m.is_debuff]
print(f"Buffs: {len(buffs)}")
print(f"Debuffs: {len(debuffs)}")
Stacking Modifiers¶
result = parser.parse_modifiers("match.dem", max_modifiers=500)
stacking = [m for m in result.modifiers if m.stack_count > 1]
print(f"Modifiers with stacks: {len(stacking)}")
for mod in stacking[:10]:
print(f" Entity {mod.parent}: {mod.stack_count} stacks")
Modifier Timeline¶
from collections import defaultdict
result = parser.parse_modifiers("match.dem", max_modifiers=1000)
# Group by tick ranges (every 1000 ticks)
timeline = defaultdict(list)
for mod in result.modifiers:
bucket = (mod.tick // 1000) * 1000
timeline[bucket].append(mod)
print("Modifier Activity Timeline:")
for tick in sorted(timeline.keys()):
mods = timeline[tick]
debuff_count = sum(1 for m in mods if m.is_debuff)
buff_count = len(mods) - debuff_count
print(f" Tick {tick:>6}: {buff_count} buffs, {debuff_count} debuffs")
Entity Modifier History¶
from collections import defaultdict
result = parser.parse_modifiers("match.dem", max_modifiers=2000)
# Group modifiers by parent entity
entity_mods = defaultdict(list)
for mod in result.modifiers:
entity_mods[mod.parent].append(mod)
# Find entities with most modifiers
sorted_entities = sorted(entity_mods.items(), key=lambda x: -len(x[1]))
print("Entities with Most Modifiers:")
for entity_id, mods in sorted_entities[:10]:
debuff_count = sum(1 for m in mods if m.is_debuff)
aura_count = sum(1 for m in mods if m.is_aura)
print(f" Entity {entity_id}: {len(mods)} total ({debuff_count} debuffs, {aura_count} auras)")
Long Duration Debuffs¶
result = parser.parse_modifiers("match.dem", max_modifiers=1000)
# Find long-duration debuffs (potential stuns/silences)
long_debuffs = [
m for m in result.modifiers
if m.is_debuff and m.duration > 2.0
]
print(f"Long duration debuffs (>2s): {len(long_debuffs)}")
for mod in sorted(long_debuffs, key=lambda m: -m.duration)[:10]:
print(f" Duration: {mod.duration:.1f}s on entity {mod.parent}")
Combining with Entity Queries¶
Since modifiers reference entities by handle, you can combine with entity queries:
# Get modifiers
mods_result = parser.parse_modifiers("match.dem", max_modifiers=200)
# Get hero entities for reference
entities_result = parser.query_entities(
"match.dem",
class_filter="Hero",
property_filter=["m_iHealth"],
max_entities=10
)
# Build entity index map
entity_map = {e.index: e.class_name for e in entities_result.entities}
# Report modifiers on known entities
for mod in mods_result.modifiers[:20]:
entity_name = entity_map.get(mod.parent, f"Unknown({mod.parent})")
mod_type = "DEBUFF" if mod.is_debuff else "BUFF"
print(f"{mod_type} on {entity_name}")
Aura Effects¶
Auras are special modifiers that affect units in an area:
result = parser.parse_modifiers("match.dem", auras_only=True, max_modifiers=300)
print("Aura Analysis:")
print("-" * 50)
# Group by caster
from collections import defaultdict
caster_auras = defaultdict(list)
for mod in result.modifiers:
caster_auras[mod.caster].append(mod)
print(f"Unique aura casters: {len(caster_auras)}")
for caster, auras in sorted(caster_auras.items(), key=lambda x: -len(x[1]))[:5]:
affected_units = len(set(m.parent for m in auras))
print(f" Caster {caster}: {len(auras)} aura applications to {affected_units} units")
Performance Tips¶
- Set max_modifiers - Modifiers can be numerous in long matches
- Use auras_only - When only interested in aura effects
- Filter client-side - Parse once, filter the results multiple times
# Efficient: get all modifiers once
all_mods = parser.parse_modifiers("match.dem", max_modifiers=2000)
# Filter in Python
debuffs = [m for m in all_mods.modifiers if m.is_debuff]
auras = [m for m in all_mods.modifiers if m.is_aura]
permanent = [m for m in all_mods.modifiers if m.duration < 0]
Common Modifier Patterns¶
Permanent Buffs (Passives/Items)¶
Control Effects (Stuns/Roots)¶
# Long-duration debuffs are often control effects
control_effects = [
m for m in result.modifiers
if m.is_debuff and 0 < m.duration <= 5.0
]
DoT/HoT Effects¶
# Short-duration stackable effects
dot_hot = [
m for m in result.modifiers
if m.stack_count > 0 and 0 < m.duration < 15
]
Important Notes¶
Note
Modifiers track when effects are applied. The parent and caster fields are entity handles, not player IDs. Use entity queries to resolve these to unit types.
Duration Values¶
| Duration | Meaning |
|---|---|
-1 |
Permanent (passives, items) |
0 |
Instant effect |
> 0 |
Timed effect in seconds |
Entity Handles¶
The parent, caster, and ability fields are entity handles:
- Use entity queries to get entity details by index
- Handles may reference entities no longer in the game
- Handle 0 typically means no specific source