From 5cde64c99372c68df95dd425462732959c4cbc12 Mon Sep 17 00:00:00 2001 From: Peter Lord Date: Thu, 9 Jul 2026 22:43:03 -0700 Subject: [PATCH] Capture starting Plating for enemies that apply it in a helper Lagavulin Matriarch's page showed no starting Plating. The monster parser scans AfterAddedToRoom for PowerCmd.Apply<...> calls, but Lagavulin delegates to a private Sleep() helper (await Sleep()) and applies its Plating there, so the scan missed it. Frog Knight, which applies Plating inline in AfterAddedToRoom, was already captured. Follow local same-class method calls from AfterAddedToRoom into their bodies before scanning, so powers applied one hop away are captured too. Verified against the decompiled source: the only monster whose innate_powers changes is Lagavulin Matriarch, which now carries Plating 12 (and Asleep 3, both applied at combat start); every other monster is byte-identical. Data regenerated for all 14 languages on both channels. --- backend/app/parsers/monster_parser.py | 33 ++++++++++++++++++++++++++- data-beta/v0.108.0/deu/monsters.json | 11 ++++++++- data-beta/v0.108.0/eng/monsters.json | 11 ++++++++- data-beta/v0.108.0/esp/monsters.json | 11 ++++++++- data-beta/v0.108.0/fra/monsters.json | 11 ++++++++- data-beta/v0.108.0/ita/monsters.json | 11 ++++++++- data-beta/v0.108.0/jpn/monsters.json | 11 ++++++++- data-beta/v0.108.0/kor/monsters.json | 11 ++++++++- data-beta/v0.108.0/pol/monsters.json | 11 ++++++++- data-beta/v0.108.0/ptb/monsters.json | 11 ++++++++- data-beta/v0.108.0/rus/monsters.json | 11 ++++++++- data-beta/v0.108.0/spa/monsters.json | 11 ++++++++- data-beta/v0.108.0/tha/monsters.json | 11 ++++++++- data-beta/v0.108.0/tur/monsters.json | 11 ++++++++- data-beta/v0.108.0/zhs/monsters.json | 11 ++++++++- data/deu/monsters.json | 11 ++++++++- data/eng/monsters.json | 11 ++++++++- data/esp/monsters.json | 11 ++++++++- data/fra/monsters.json | 11 ++++++++- data/ita/monsters.json | 11 ++++++++- data/jpn/monsters.json | 11 ++++++++- data/kor/monsters.json | 11 ++++++++- data/pol/monsters.json | 11 ++++++++- data/ptb/monsters.json | 11 ++++++++- data/rus/monsters.json | 11 ++++++++- data/spa/monsters.json | 11 ++++++++- data/tha/monsters.json | 11 ++++++++- data/tur/monsters.json | 11 ++++++++- data/zhs/monsters.json | 11 ++++++++- 29 files changed, 312 insertions(+), 29 deletions(-) diff --git a/backend/app/parsers/monster_parser.py b/backend/app/parsers/monster_parser.py index 47e850f4..616d679e 100644 --- a/backend/app/parsers/monster_parser.py +++ b/backend/app/parsers/monster_parser.py @@ -1042,6 +1042,37 @@ def parse_single_monster( depth -= 1 i += 1 init_block = content[start : i - 1] + # AfterAddedToRoom often delegates its combat-start setup to a private helper + # rather than writing every PowerCmd.Apply inline. Lagavulin Matriarch, for + # instance, calls `await Sleep();` and applies its innate Plating inside + # Sleep(). Follow local same-class method calls (await Foo(...) where Foo is a + # method defined in this file, not base.X / Cmd.X) so those applied powers are + # captured too. Bounded to a couple of levels with a visited set. + scan_block = init_block + seen_helpers: set[str] = set() + frontier = [init_block] + hops = 0 + while frontier and hops < 8: + block = frontier.pop() + for call in re.finditer(r"\bawait\s+(\w+)\s*\(", block): + helper = call.group(1) + if helper in seen_helpers or helper == "AfterAddedToRoom": + continue + # Only follow methods actually DEFINED in this class (a private/ + # protected/etc. helper); the modifier prefix excludes bare framework + # calls and `await base.X()` (which has no local definition here). + helper_body = _extract_method_body( + content, + r"(?:private|protected|internal|public)[^\n;{]*\b" + + re.escape(helper) + + r"\s*\(", + ) + if helper_body is None: + continue + seen_helpers.add(helper) + scan_block += "\n" + helper_body + frontier.append(helper_body) + hops += 1 # v0.104+ added an optional context arg before the target, same as the # move-effects regex above: # OLD: PowerCmd.Apply(base.Creature, 3m, ...) @@ -1054,7 +1085,7 @@ def parse_single_monster( # no `` token and is still not captured here. for pm in re.finditer( r"PowerCmd\.Apply<(\w+)>\(\s*(?:new\s+\w+\([^)]*\)\s*,\s*)?[\w.]+\s*,\s*(\w+?)m?\b", - init_block, + scan_block, ): power_name = pm.group(1).replace("Power", "") amount_ref = pm.group(2) diff --git a/data-beta/v0.108.0/deu/monsters.json b/data-beta/v0.108.0/deu/monsters.json index 08ed3eb7..fadadd21 100644 --- a/data-beta/v0.108.0/deu/monsters.json +++ b/data-beta/v0.108.0/deu/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/eng/monsters.json b/data-beta/v0.108.0/eng/monsters.json index 3cd13bd2..e4867942 100644 --- a/data-beta/v0.108.0/eng/monsters.json +++ b/data-beta/v0.108.0/eng/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/esp/monsters.json b/data-beta/v0.108.0/esp/monsters.json index 27bf8491..0b5ccebc 100644 --- a/data-beta/v0.108.0/esp/monsters.json +++ b/data-beta/v0.108.0/esp/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/fra/monsters.json b/data-beta/v0.108.0/fra/monsters.json index 85741429..19156690 100644 --- a/data-beta/v0.108.0/fra/monsters.json +++ b/data-beta/v0.108.0/fra/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/ita/monsters.json b/data-beta/v0.108.0/ita/monsters.json index e426f1cc..4f8cfadc 100644 --- a/data-beta/v0.108.0/ita/monsters.json +++ b/data-beta/v0.108.0/ita/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/jpn/monsters.json b/data-beta/v0.108.0/jpn/monsters.json index dbeb822b..732ff71e 100644 --- a/data-beta/v0.108.0/jpn/monsters.json +++ b/data-beta/v0.108.0/jpn/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/kor/monsters.json b/data-beta/v0.108.0/kor/monsters.json index 83c1169b..ed924755 100644 --- a/data-beta/v0.108.0/kor/monsters.json +++ b/data-beta/v0.108.0/kor/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/pol/monsters.json b/data-beta/v0.108.0/pol/monsters.json index 075f625a..fa52d9fa 100644 --- a/data-beta/v0.108.0/pol/monsters.json +++ b/data-beta/v0.108.0/pol/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/ptb/monsters.json b/data-beta/v0.108.0/ptb/monsters.json index 28ee0386..55a5fbf9 100644 --- a/data-beta/v0.108.0/ptb/monsters.json +++ b/data-beta/v0.108.0/ptb/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/rus/monsters.json b/data-beta/v0.108.0/rus/monsters.json index e3fa5ef9..dcf87aa5 100644 --- a/data-beta/v0.108.0/rus/monsters.json +++ b/data-beta/v0.108.0/rus/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/spa/monsters.json b/data-beta/v0.108.0/spa/monsters.json index 8d9e2a9b..e21772b3 100644 --- a/data-beta/v0.108.0/spa/monsters.json +++ b/data-beta/v0.108.0/spa/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/tha/monsters.json b/data-beta/v0.108.0/tha/monsters.json index ec506bee..fd8e5eed 100644 --- a/data-beta/v0.108.0/tha/monsters.json +++ b/data-beta/v0.108.0/tha/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/tur/monsters.json b/data-beta/v0.108.0/tur/monsters.json index 90ba6b29..16c4af11 100644 --- a/data-beta/v0.108.0/tur/monsters.json +++ b/data-beta/v0.108.0/tur/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data-beta/v0.108.0/zhs/monsters.json b/data-beta/v0.108.0/zhs/monsters.json index 5e7e93f1..ba547968 100644 --- a/data-beta/v0.108.0/zhs/monsters.json +++ b/data-beta/v0.108.0/zhs/monsters.json @@ -4575,7 +4575,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/deu/monsters.json b/data/deu/monsters.json index bff9c476..2411cf0c 100644 --- a/data/deu/monsters.json +++ b/data/deu/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/eng/monsters.json b/data/eng/monsters.json index 6a985c41..6678fc63 100644 --- a/data/eng/monsters.json +++ b/data/eng/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/esp/monsters.json b/data/esp/monsters.json index 8fa9331d..bf899cd8 100644 --- a/data/esp/monsters.json +++ b/data/esp/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/fra/monsters.json b/data/fra/monsters.json index 2025139d..6244dd94 100644 --- a/data/fra/monsters.json +++ b/data/fra/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/ita/monsters.json b/data/ita/monsters.json index e52fe9b8..1989ca85 100644 --- a/data/ita/monsters.json +++ b/data/ita/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/jpn/monsters.json b/data/jpn/monsters.json index 68b57ab1..adac2991 100644 --- a/data/jpn/monsters.json +++ b/data/jpn/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/kor/monsters.json b/data/kor/monsters.json index 02bd0786..e7c402af 100644 --- a/data/kor/monsters.json +++ b/data/kor/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/pol/monsters.json b/data/pol/monsters.json index d2bf5dfc..d385280f 100644 --- a/data/pol/monsters.json +++ b/data/pol/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/ptb/monsters.json b/data/ptb/monsters.json index c8c22d2d..4f06a753 100644 --- a/data/ptb/monsters.json +++ b/data/ptb/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/rus/monsters.json b/data/rus/monsters.json index e7cbbf93..30448a7a 100644 --- a/data/rus/monsters.json +++ b/data/rus/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/spa/monsters.json b/data/spa/monsters.json index baec3ced..a7ec913a 100644 --- a/data/spa/monsters.json +++ b/data/spa/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/tha/monsters.json b/data/tha/monsters.json index 184f54ea..79352fdf 100644 --- a/data/tha/monsters.json +++ b/data/tha/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/tur/monsters.json b/data/tur/monsters.json index 10e447d0..7505c404 100644 --- a/data/tur/monsters.json +++ b/data/tur/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP", diff --git a/data/zhs/monsters.json b/data/zhs/monsters.json index 61067407..55cf36da 100644 --- a/data/zhs/monsters.json +++ b/data/zhs/monsters.json @@ -4572,7 +4572,16 @@ "is_weak": false } ], - "innate_powers": null, + "innate_powers": [ + { + "power_id": "PLATING", + "amount": 12 + }, + { + "power_id": "ASLEEP", + "amount": 3 + } + ], "attack_pattern": { "type": "conditional", "initial_move": "SLEEP",