basic noita parsing

This commit is contained in:
2026-05-10 01:45:29 +02:00
parent 119fdc2a51
commit 69b6b46ee2
14 changed files with 1117 additions and 38 deletions
+291
View File
@@ -0,0 +1,291 @@
"""
Decode a polylan_mod_log.txt.
Hash format: sha1(seed|timestamp|id) — timestamp is bound into the hash so
it cannot be altered without breaking the signature.
Seed-less entries (INIT, DEBUG, mod checks) use sha1(id) with no seed or
timestamp — those are resolved via a static lookup.
Usage:
python decode_log.py [path/to/polylan_mod_log.txt]
Default path: ~/.local/share/Steam/steamapps/common/Noita/polylan_mod_log.txt
"""
import hashlib
import re
from functools import cache
from noita.services.spells import ALL_SPELLS, ALL_PERKS
SEED_POOL = [
# General good seeds
3154823,
3718311,
10064758,
123156801,
1024089369,
1026967166,
# Pacifist seeds
177795258,
520542929,
10600249,
25300740,
21875589,
24085389,
59775105,
44190726,
1039649471,
1072607354,
# Perk combo seeds
839747651,
839844768,
840909713,
839959129,
840016192,
840039886,
840398606,
840439045,
840457463,
840492754,
840507802,
840513742,
840542079,
840574169,
840610974,
840626894,
840872436,
840894605,
841221188,
]
DEATH_PENALTY = 1
# All scoreable events: base 1 pt for every spell and perk, overrides below.
POINTS = {
# ── Spells ───────────────────────────────────────────────────────────────
**{sid: 1 for sid in ALL_SPELLS},
"ADD_TRIGGER": 10,
"NOLLA": 10,
"CHAOTIC_TRANSMUTATION": 10,
"DUPLICATE": 5,
"OMEGA": 10,
"HEALING_BOLT": 5,
# ── Perks ─────────────────────────────────────────────────────────────────
**{pid: 1 for pid in ALL_PERKS},
"EDIT_WANDS_EVERYWHERE": 10,
# ── Spell combos ─────────────────────────────────────────────────────────
"PING_PONG_DRILL": 10,
"HEAVY_SHOT_DISC": 10,
"TOUCH_OF_ANY": 5,
"TWO_ARC_MODIFIERS": 10,
"TWO_TRAIL_MODIFIERS": 10,
# ── Perk combos ──────────────────────────────────────────────────────────
"CRIMSON_ALCHEMIST": 15,
"GREEDY_GOBLIN_KING": 15,
"STORM_TOUCHED_ASCENDANT": 15,
"ARCHMAGE_OF_CONTROL": 15,
"HAUNTED_MAGE": 15,
"GLASS_CANNON_MESSIAH": 15,
"INFINITE_ENGINE": 15,
"PERFECT_ACCURACY_LOOP": 15,
"HOMING_DEATH_SWARM": 15,
"UNTOUCHABLE_FIELD": 15,
"ELECTRIC_SUSTAIN_LOOP": 15,
"IMMORTAL_LEECH_CORE": 15,
"PROJECTILE_OVERLOAD": 15,
"CLOSE_RANGE_DEATH_MACHINE": 15,
"CRITICAL_MASS": 15,
"HOLY_MOUNTAIN_ABUSER": 15,
"DEFLECTOR_MATRIX": 15,
"STORMBORNE_LEVITATOR": 15,
# ── Objectives ───────────────────────────────────────────────────────────
"HP_200": 5,
"HP_500": 5,
"HP_2000": 5,
"HP_5000": 5,
"GOLD_1000": 5,
"GOLD_10000": 5,
"GOLD_100000": 5,
"GOLD_1000000": 5,
**{f"ORB_{i}": 5 for i in range(34)},
"FIND_AMBROSIA": 10,
"WAND_MANA_500": 10,
"WAND_MANA_1000": 10,
"WAND_MANA_1500": 10,
"WAND_CAPACITY_10": 10,
"WAND_CAPACITY_20": 10,
"BOSS_KILL": 100,
"CRIMSON_ALCHEMIST-BOSS_KILL": 100,
"GREEDY_GOBLIN_KING-BOSS_KILL": 100,
"STORM_TOUCHED_ASCENDANT-BOSS_KILL": 100,
"ARCHMAGE_OF_CONTROL-BOSS_KILL": 100,
"HAUNTED_MAGE-BOSS_KILL": 100,
"GLASS_CANNON_MESSIAH-BOSS_KILL": 100,
"INFINITE_ENGINE-BOSS_KILL": 100,
"PERFECT_ACCURACY_LOOP-BOSS_KILL": 100,
"HOMING_DEATH_SWARM-BOSS_KILL": 100,
"UNTOUCHABLE_FIELD-BOSS_KILL": 100,
"ELECTRIC_SUSTAIN_LOOP-BOSS_KILL": 100,
"IMMORTAL_LEECH_CORE-BOSS_KILL": 100,
"PROJECTILE_OVERLOAD-BOSS_KILL": 100,
"CLOSE_RANGE_DEATH_MACHINE-BOSS_KILL": 100,
"CRITICAL_MASS-BOSS_KILL": 100,
"HOLY_MOUNTAIN_ABUSER-BOSS_KILL": 100,
"DEFLECTOR_MATRIX-BOSS_KILL": 100,
"STORMBORNE_LEVITATOR-BOSS_KILL": 100,
}
# Perk-combo IDs — used to award a per-combo boss-kill bonus.
PERK_COMBO_IDS = {
"CRIMSON_ALCHEMIST",
"GREEDY_GOBLIN_KING",
"STORM_TOUCHED_ASCENDANT",
"ARCHMAGE_OF_CONTROL",
"HAUNTED_MAGE",
"GLASS_CANNON_MESSIAH",
"INFINITE_ENGINE",
"PERFECT_ACCURACY_LOOP",
"HOMING_DEATH_SWARM",
"UNTOUCHABLE_FIELD",
"ELECTRIC_SUSTAIN_LOOP",
"IMMORTAL_LEECH_CORE",
"PROJECTILE_OVERLOAD",
"CLOSE_RANGE_DEATH_MACHINE",
"CRITICAL_MASS",
"HOLY_MOUNTAIN_ABUSER",
"DEFLECTOR_MATRIX",
"STORMBORNE_LEVITATOR",
}
BOSS_KILL_COMBO_BONUS = 100 # default bonus per active perk combo on boss kill
# IDs tried with the seed+timestamp scheme.
_ALL_IDS = list(POINTS.keys()) + ["DEATH"]
# Seed-less hashes (sha1(id) only, no seed, no timestamp).
_STATIC_LOOKUP = {
hashlib.sha1(k.encode()).hexdigest(): k
for k in ["-", "DEBUG", "polylan-mod", "cheatgui", "alchemy_recipes_display"]
}
def _sha1(text: str) -> str:
return hashlib.sha1(text.encode("utf-8")).hexdigest()
@cache
def resolve(
hash_val: str, ts: str, preferred_seed: int | None = None
) -> tuple[str | None, int | None]:
"""Return (name, seed) or (None, None). preferred_seed is tried first."""
if hash_val in _STATIC_LOOKUP:
return _STATIC_LOOKUP[hash_val], None
seeds = (
[preferred_seed] + [s for s in SEED_POOL if s != preferred_seed]
if preferred_seed is not None
else SEED_POOL
)
for seed in seeds:
prefix = f"{seed}|{ts}|"
for name in _ALL_IDS:
if _sha1(prefix + name) == hash_val:
return name, seed
return None, None
def parse_log(file) -> list:
entries = []
for il, line in enumerate(file.split("\n")):
m = re.match(r"\[(.+?)\] ([0-9a-f]{40})", line.rstrip())
if m:
entries.append({"ts": m.group(1), "hash": m.group(2)})
continue
print(f"Unable to parse line number {il:>4}: {line.strip()}??")
return entries
def decode(file) -> None:
entries = parse_log(file)
if not entries:
print("No entries found in log.")
return
seen = set()
total = 0
deaths = 0
have_init = False
have_debug = False
known_seed = None # cached once first seeded entry is resolved
current_run_perk_combos = set() # perk combos seen since the last "-" entry
for entry in entries:
name, seed = resolve(entry["hash"], entry["ts"], known_seed)
if name is None:
print(f" ???? (unresolved) {entry['hash']} ts: {entry['ts']}")
continue
if seed is not None and known_seed is None:
known_seed = seed
if name == "-":
have_init = True
current_run_perk_combos = set()
continue
if name == "DEBUG":
have_debug = True
continue
if name == "DEATH":
deaths += 1
continue
# skip mod-presence entries
if name not in POINTS:
continue
if name in seen:
continue
if name not in {"BOSS_KILL"}:
seen.add(name)
if name in PERK_COMBO_IDS:
current_run_perk_combos.add(name)
pts = POINTS.get(name, 0)
if pts:
print(f" +{pts:>4} {name:<40} first seen: {entry['ts']}")
total += pts
if name == "BOSS_KILL":
for combo_id in sorted(current_run_perk_combos):
bonus_key = f"{combo_id}-BOSS_KILL"
if bonus_key not in seen:
seen.add(bonus_key)
bonus_pts = POINTS.get(bonus_key, BOSS_KILL_COMBO_BONUS)
print(f" +{bonus_pts:>4} {bonus_key:<40} combo bonus")
total += bonus_pts
death_deduction = deaths * DEATH_PENALTY
if deaths:
print(
f" -{death_deduction:>4} ({deaths} death{'s' if deaths > 1 else ''} × {DEATH_PENALTY} pts)"
)
if have_init:
print(
f"\nTotal: {total - death_deduction} pts ({total} earned {death_deduction} penalty)"
)
if have_debug:
print("Note: DEBUG mode was active during at least one session.")
@@ -0,0 +1,40 @@
from noita.models import LogfileSubmission, Objectiv
from noita.services.decode import parse_log, resolve
from collections import Counter
def parse_objectives_from_logfile(logfile: LogfileSubmission) -> Counter:
"""Parse a log file, and output a count for each ID."""
file_data = logfile.file.read().decode()
ids = []
for entry in parse_log(file_data):
idx, _seed = resolve(entry["hash"], entry["ts"])
if idx:
ids.append(idx)
return Counter(ids)
def parse_objectives_and_store(logfile: LogfileSubmission) -> None:
"""Parse a logfile and store output."""
if not logfile.user:
return
counter = parse_objectives_from_logfile(logfile)
for idx, count in counter.items():
if idx in {"-", "DEBUG"}:
continue
obj, created = Objectiv.objects.get_or_create(
objectiv_id=idx,
user=logfile.user,
)
obj.count += count
obj.save(update_fields=["count"])
+535
View File
@@ -0,0 +1,535 @@
ALL_SPELLS = [
"FUNKY_SPELL",
"ACIDSHOT",
"BLACK_HOLE",
"BLACK_HOLE_DEATH_TRIGGER",
"BOMB",
"BOMB_CART",
"BUBBLESHOT",
"BUBBLESHOT_TRIGGER",
"AIR_BULLET",
"CHAIN_BOLT",
"CHAINSAW",
"CURSED_ORB",
"ANTIHEAL",
"DEATH_CROSS",
"DEATH_CROSS_BIG",
"LASER_EMITTER_FOUR",
"POWERDIGGER",
"DIGGER",
"PIPE_BOMB",
"PIPE_BOMB_DEATH_TRIGGER",
"GRENADE_LARGE",
"DYNAMITE",
"CRUMBLING_EARTH",
"TENTACLE_PORTAL",
"SLOW_BULLET",
"SLOW_BULLET_TRIGGER",
"SLOW_BULLET_TIMER",
"EXPANDING_ORB",
"FIREBALL",
"GRENADE",
"GRENADE_TRIGGER",
"GRENADE_TIER_2",
"GRENADE_TIER_3",
"GRENADE_ANTI",
"FIREBOMB",
"FIREWORK",
"FLAMETHROWER",
"GLITTER_BOMB",
"LANCE",
"GLUE_SHOT",
"HEAL_BULLET",
"LANCE_HOLY",
"BOMB_HOLY",
"BOMB_HOLY_GIGA",
"HOOK",
"ICEBALL",
"LASER",
"LIGHTNING",
"THUNDERBALL",
"BALL_LIGHTNING",
"LUMINOUS_DRILL",
"LASER_LUMINOUS_DRILL",
"BULLET",
"BULLET_TRIGGER",
"BULLET_TIMER",
"HEAVY_BULLET",
"HEAVY_BULLET_TRIGGER",
"HEAVY_BULLET_TIMER",
"MAGIC_SHIELD",
"BIG_MAGIC_SHIELD",
"ROCKET",
"ROCKET_TIER_2",
"ROCKET_TIER_3",
"METEOR",
"MIST_BLOOD",
"MIST_ALCOHOL",
"MIST_SLIME",
"MIST_RADIOACTIVE",
"BUCKSHOT",
"MEGALASER",
"EXPLODING_DUCKS",
"FREEZING_GAZE",
"INFESTATION",
"NUKE",
"NUKE_GIGA",
"DARKFLAME",
"GLOWING_BOLT",
"LASER_EMITTER",
"LASER_EMITTER_CUTTER",
"POLLEN",
"SPORE_POD",
"PROPANE_TANK",
"RANDOM_PROJECTILE",
"SUMMON_ROCK",
"DISC_BULLET",
"DISC_BULLET_BIG",
"DISC_BULLET_BIGGER",
"SLIMEBALL",
"LIGHT_BULLET",
"LIGHT_BULLET_TRIGGER",
"LIGHT_BULLET_TRIGGER_2",
"LIGHT_BULLET_TIMER",
"RUBBER_BALL",
"ARROW",
"BOUNCY_ORB",
"BOUNCY_ORB_TIMER",
"SPIRAL_SHOT",
"SPITTER",
"SPITTER_TIMER",
"SPITTER_TIER_2",
"SPITTER_TIER_2_TIMER",
"SPITTER_TIER_3",
"SPITTER_TIER_3_TIMER",
"EXPLODING_DEER",
"SUMMON_EGG",
"TNTBOX",
"TNTBOX_BIG",
"FISH",
"SUMMON_HOLLOW_EGG",
"MISSILE",
"PEBBLE",
"TENTACLE",
"TENTACLE_TIMER",
"TELEPORT_PROJECTILE_CLOSER",
"TELEPORT_PROJECTILE_STATIC",
"SWAPPER_PROJECTILE",
"TELEPORT_PROJECTILE",
"TELEPORT_PROJECTILE_SHORT",
"MINE",
"MINE_DEATH_TRIGGER",
"WHITE_HOLE",
"WORM_SHOT",
"WALL_HORIZONTAL",
"WALL_VERTICAL",
"WALL_SQUARE",
"REGENERATION_FIELD",
"FREEZE_FIELD",
"LEVITATION_FIELD",
"TELEPORTATION_FIELD",
"BERSERK_FIELD",
"SHIELD_FIELD",
"ELECTROCUTION_FIELD",
"POLYMORPH_FIELD",
"CHAOS_POLYMORPH_FIELD",
"CLOUD_WATER",
"CLOUD_OIL",
"CLOUD_BLOOD",
"CLOUD_ACID",
"CLOUD_THUNDER",
"DESTRUCTION",
"BOMB_DETONATOR",
"PURPLE_EXPLOSION_FIELD",
"WORM_RAIN",
"METEOR_RAIN",
"SWARM_FLY",
"SWARM_FIREBUG",
"SWARM_WASP",
"DELAYED_SPELL",
"MASS_POLYMORPH",
"PROJECTILE_THUNDER_FIELD",
"PROJECTILE_GRAVITY_FIELD",
"PROJECTILE_TRANSMUTATION_FIELD",
"RANDOM_STATIC_PROJECTILE",
"WHITE_HOLE_BIG",
"BLACK_HOLE_BIG",
"BLACK_HOLE_GIGA",
"THUNDER_BLAST",
"FIRE_BLAST",
"EXPLOSION_LIGHT",
"POISON_BLAST",
"EXPLOSION",
"ALCOHOL_BLAST",
"WHITE_HOLE_GIGA",
"FRIEND_FLY",
"VACUUM_POWDER",
"VACUUM_LIQUID",
"VACUUM_ENTITIES",
"CLUSTERMOD",
"MANA_REDUCE",
"ARC_POISON",
"ARC_FIRE",
"ARC_GUNPOWDER",
"ARC_ELECTRIC",
"ROCKET_DOWNWARDS",
"ROCKET_OCTAGON",
"BOUNCE",
"BOUNCE_SPARK",
"BOUNCE_LASER",
"REMOVE_BOUNCE",
"BOUNCE_SMALL_EXPLOSION",
"BOUNCE_HOLE",
"BOUNCE_EXPLOSION",
"BOUNCE_LARPA",
"BOUNCE_LIGHTNING",
"BOUNCE_LASER_EMITTER",
"EXPLOSION_TINY",
"HITFX_CRITICAL_BLOOD",
"HITFX_CRITICAL_OIL",
"HITFX_CRITICAL_WATER",
"HITFX_BURNING_CRITICAL_HIT",
"CRITICAL_HIT",
"AREA_DAMAGE",
"BLOODLUST",
"DAMAGE",
"DAMAGE_RANDOM",
"DAMAGE_FOREVER",
"ZERO_DAMAGE",
"HEAVY_SHOT",
"LIGHT_SHOT",
"CRUMBLING_EARTH_PROJECTILE",
"FREEZE",
"ELECTRIC_CHARGE",
"HITFX_EXPLOSION_ALCOHOL",
"HITFX_EXPLOSION_ALCOHOL_GIGA",
"HITFX_EXPLOSION_SLIME",
"HITFX_EXPLOSION_SLIME_GIGA",
"HITFX_TOXIC_CHARM",
"COLOUR_RED",
"COLOUR_ORANGE",
"COLOUR_YELLOW",
"COLOUR_GREEN",
"COLOUR_BLUE",
"COLOUR_PURPLE",
"COLOUR_RAINBOW",
"COLOUR_INVIS",
"HEAVY_SPREAD",
"KNOCKBACK",
"LARPA_CHAOS_2",
"LARPA_CHAOS",
"LARPA_DOWNWARDS",
"LARPA_DEATH",
"LARPA_UPWARDS",
"LIFETIME_DOWN",
"LIFETIME",
"CHAIN_SHOT",
"NOLLA",
"LIGHT",
"NECROMANCY",
"ORBIT_DISCS",
"ORBIT_NUKES",
"ORBIT_FIREBALLS",
"ORBIT_LARPA",
"ORBIT_LASERS",
"LINE_ARC",
"HORIZONTAL_ARC",
"GRAVITY",
"GRAVITY_ANTI",
"FLY_UPWARDS",
"FLY_DOWNWARDS",
"ORBIT_SHOT",
"TRUE_ORBIT",
"SPIRALING_SHOT",
"PINGPONG_PATH",
"PHASING_ARC",
"CHAOTIC_ARC",
"SINEWAVE",
"HOMING_WAND",
"HOMING_CURSOR",
"HOMING_SHORT",
"AUTOAIM",
"HOMING",
"HOMING_ROTATE",
"HOMING_SHOOTER",
"ANTI_HOMING",
"HOMING_ACCELERATING",
"HOMING_AREA",
"FIREBALL_RAY_ENEMY",
"GRAVITY_FIELD_ENEMY",
"TENTACLE_RAY_ENEMY",
"LIGHTNING_RAY_ENEMY",
"HITFX_PETRIFY",
"PIERCING_SHOT",
"LASER_EMITTER_WIDER",
"QUANTUM_SPLIT",
"RANDOM_EXPLOSION",
"RANDOM_MODIFIER",
"RECOIL",
"RECOIL_DAMPER",
"RECHARGE",
"SPREAD_REDUCE",
"EXPLOSION_REMOVE",
"SLOW_BUT_STEADY",
"ENERGY_SHIELD_SHOT",
"SPEED",
"DECELERATING_SHOT",
"ACCELERATING_SHOT",
"FIZZLE",
"FLOATING_ARC",
"AVOIDING_ARC",
"CLIPPING_SHOT",
"UNSTABLE_GUNPOWDER",
"MATTER_EATER",
"EXPLOSIVE_PROJECTILE",
"FIREBALL_RAY_LINE",
"FIREBALL_RAY",
"LIGHTNING_RAY",
"TENTACLE_RAY",
"LASER_EMITTER_RAY",
"SPELLS_TO_POWER",
"ESSENCE_TO_POWER",
"ACID_TRAIL",
"FIRE_TRAIL",
"GUNPOWDER_TRAIL",
"OIL_TRAIL",
"POISON_TRAIL",
"RAINBOW_TRAIL",
"WATER_TRAIL",
"BURN_TRAIL",
"WATER_TO_POISON",
"BLOOD_TO_ACID",
"LAVA_TO_BLOOD",
"LIQUID_TO_EXPLOSION",
"TOXIC_TO_ACID",
"STATIC_TO_SAND",
"TRANSMUTATION",
"CURSE_WITHER_ELECTRICITY",
"CURSE_WITHER_EXPLOSION",
"CURSE_WITHER_MELEE",
"CURSE_WITHER_PROJECTILE",
"CURSE",
"BURST_2",
"BURST_3",
"BURST_4",
"BURST_8",
"BURST_X",
"SCATTER_2",
"SCATTER_3",
"SCATTER_4",
"I_SHAPE",
"T_SHAPE",
"PENTAGRAM_SHAPE",
"CIRCLE_SHAPE",
"Y_SHAPE",
"W_SHAPE",
"TOUCH_PISS",
"TOUCH_GRASS",
"SOILBALL",
"CIRCLE_FIRE",
"CIRCLE_ACID",
"CIRCLE_OIL",
"CIRCLE_WATER",
"MATERIAL_BLOOD",
"MATERIAL_CEMENT",
"MATERIAL_OIL",
"MATERIAL_ACID",
"MATERIAL_WATER",
"SEA_LAVA",
"SEA_ALCOHOL",
"SEA_OIL",
"SEA_WATER",
"SEA_ACID",
"SEA_ACID_GAS",
"SEA_SWAMP",
"SEA_MIMIC",
"TOUCH_BLOOD",
"TOUCH_GOLD",
"TOUCH_OIL",
"TOUCH_SMOKE",
"TOUCH_ALCOHOL",
"TOUCH_WATER",
"X_RAY",
"BLOOD_MAGIC",
"CASTER_CAST",
"I_SHOT",
"Y_SHOT",
"T_SHOT",
"W_SHOT",
"QUAD_SHOT",
"PENTA_SHOT",
"HEXA_SHOT",
"SUPER_TELEPORT_CAST",
"TELEPORT_CAST",
"LONG_DISTANCE_CAST",
"ALL_ACID",
"ALL_BLACKHOLES",
"ALL_DEATHCROSSES",
"ALL_ROCKETS",
"ALL_NUKES",
"ALL_DISCS",
"SUMMON_WANDGHOST",
"TEMPORARY_PLATFORM",
"TEMPORARY_WALL",
"MONEY_MAGIC",
"BLOOD_TO_POWER",
"RESET",
"ENERGY_SHIELD",
"ENERGY_SHIELD_SECTOR",
"TINY_GHOST",
"TORCH",
"TORCH_ELECTRIC",
"ADD_TRIGGER",
"ADD_TIMER",
"ADD_DEATH_TRIGGER",
"CESSATION",
"DIVIDE_2",
"DIVIDE_3",
"DIVIDE_4",
"DIVIDE_10",
"OMEGA",
"ZETA",
"TAU",
"SIGMA",
"PHI",
"MU",
"ALPHA",
"GAMMA",
"KANTELE_A",
"KANTELE_D",
"KANTELE_DIS",
"KANTELE_E",
"KANTELE_G",
"OCARINA_A",
"OCARINA_B",
"OCARINA_C",
"OCARINA_D",
"OCARINA_E",
"OCARINA_F",
"OCARINA_GSHARP",
"OCARINA_A2",
"RANDOM_SPELL",
"DRAW_RANDOM",
"DRAW_RANDOM_X3",
"DRAW_3_RANDOM",
"IF_PROJECTILE",
"IF_HP",
"IF_ENEMY",
"IF_HALF",
"IF_ELSE",
"IF_END",
"DUPLICATE",
"SUMMON_PORTAL",
"ALL_SPELLS",
]
ALL_PERKS = [
"CRITICAL_HIT",
"BREATH_UNDERWATER",
"EXTRA_MONEY",
"EXTRA_MONEY_TRICK_KILL",
"GOLD_IS_FOREVER",
"TRICK_BLOOD_MONEY",
"EXPLODING_GOLD",
"HOVER_BOOST",
"FASTER_LEVITATION",
"MOVEMENT_FASTER",
"LOW_GRAVITY",
"HIGH_GRAVITY",
"SPEED_DIVER",
"STRONG_KICK",
"TELEKINESIS",
"REPELLING_CAPE",
"EXPLODING_CORPSES",
"SAVING_GRACE",
"INVISIBILITY",
"GLOBAL_GORE",
"REMOVE_FOG_OF_WAR",
"LEVITATION_TRAIL",
"VAMPIRISM",
"EXTRA_HP",
"HEARTS_MORE_EXTRA_HP",
"GLASS_CANNON",
"LOW_HP_DAMAGE_BOOST",
"RESPAWN",
"WORM_ATTRACTOR",
"WORM_DETRACTOR",
"RADAR_ENEMY",
"FOOD_CLOCK",
"WAND_RADAR",
"ITEM_RADAR",
"MOON_RADAR",
"PROTECTION_FIRE",
"PROTECTION_RADIOACTIVITY",
"PROTECTION_EXPLOSION",
"PROTECTION_MELEE",
"PROTECTION_ELECTRICITY",
"TELEPORTITIS",
"TELEPORTITIS_DODGE",
"STAINLESS_ARMOUR",
"EDIT_WANDS_EVERYWHERE",
"NO_WAND_EDITING",
"WAND_EXPERIMENTER",
"ADVENTURER",
"ABILITY_ACTIONS_MATERIALIZED",
"PROJECTILE_HOMING",
"PROJECTILE_HOMING_SHOOTER",
"UNLIMITED_SPELLS",
"FREEZE_FIELD",
"FIRE_GAS",
"DISSOLVE_POWDERS",
"BLEED_SLIME",
"BLEED_OIL",
"BLEED_GAS",
"SHIELD",
"REVENGE_EXPLOSION",
"REVENGE_TENTACLE",
"REVENGE_RATS",
"REVENGE_BULLET",
"ATTACK_FOOT",
"LEGGY_FEET",
"PLAGUE_RATS",
"VOMIT_RATS",
"CORDYCEPS",
"MOLD",
"WORM_SMALLER_HOLES",
"PROJECTILE_REPULSION",
"RISKY_CRITICAL",
"FUNGAL_DISEASE",
"PROJECTILE_SLOW_FIELD",
"PROJECTILE_REPULSION_SECTOR",
"PROJECTILE_EATER_SECTOR",
"ORBIT",
"ANGRY_GHOST",
"HUNGRY_GHOST",
"DEATH_GHOST",
"HOMUNCULUS",
"ELECTRICITY",
"ATTRACT_ITEMS",
"EXTRA_KNOCKBACK",
"LOWER_SPREAD",
"LOW_RECOIL",
"BOUNCE",
"FAST_PROJECTILES",
"ALWAYS_CAST",
"EXTRA_MANA",
"NO_MORE_SHUFFLE",
"NO_MORE_KNOCKBACK",
"DUPLICATE_PROJECTILE",
"FASTER_WANDS",
"EXTRA_SLOTS",
"CONTACT_DAMAGE",
"EXTRA_PERK",
"PERKS_LOTTERY",
"GAMBLE",
"EXTRA_SHOP_ITEM",
"GENOME_MORE_HATRED",
"GENOME_MORE_LOVE",
"PEACE_WITH_GODS",
"MANA_FROM_KILLS",
"ANGRY_LEVITATION",
"LASER_AIM",
"PERSONAL_LASER",
"MEGA_BEAM_STONE",
"IRON_STOMACH",
]