# ALARMHAT Analysis ## Purpose This note records the current evidence-backed read of exported `ALARMHAT` pseudocode and what the class most likely means in gameplay. The goal is not to force a final rename. The goal is to state what the script definitely does, what it probably does, and where the remaining uncertainty sits. ## Sources used - exported pseudocode: `USECODE/EUSECODE_extracted/pseudocode/ALARMHAT/slot_0A_equip.txt` - class/event index rows for `ALARMHAT` - raw linear disassembly in `K:/ghidra/crusader-disasm/crusader_disasm.txt` - nearby alarm-family comparators: - `ALARMBOX` - `ALRMTRIG` - `ALARM_NS` - `ALARM_EW` ## Short version `ALARMHAT` is not a general many-event alarm controller. In the extracted corpus it has one live body: slot `0x0A` (`equip`). That body behaves like an alarm-family state controller attached to an item. It does two different things depending on the current frame of the item: 1. in frame `0`, it searches nearby shape `0x04D0` objects and equips qualifying ones with mode `0x17` 2. in non-zero frames, it first requires the item to be on-screen, then performs a nearby actor/family scan, and if that passes it searches nearby shape `0x04D0` objects and equips qualifying ones with mode `0x15` The likely gameplay read is: `ALARMHAT` is a local alarm-state driver that flips nearby helper objects or actors into one of two equipment/activation states, with the second state gated by player-visible activity near the item. ## Structural facts From `class_event_index.tsv`: - class: `ALARMHAT` - class id: `0x0561` - only decoded non-zero slot: `0x0A equip` - body window: `0x00D4..0x025F` - body length: `395` bytes From the debug trailer/local names in the exported body: - locals currently render as `referent`, `var`, `item`, and `npc` Those local names are useful hints, but the behavior matters more than the variable spelling. ## Direct script behavior The body begins with the standard alarm-family setup: ```text set_info(0x0211, *(arg_06)); process_exclude(); ``` That matches `ALARMBOX::equip`, which also begins with `set_info(0x0211, *(arg_06)); process_exclude();`. After that, the script splits on `Item.getFrame(arg_06)`. ### Branch 1: frame == 0 The raw disassembly shows a loop-selector sequence equivalent to: - search nearby items - constrain by `item->shape == 0x04D0` - use the current item as the search origin For each matching object: - call `Item.getFrame(item)` - only continue on frame `0` - call `Item::I_equip(pid, 0x17, item)` - `suspend` So the first branch is not sounding an alarm by itself. It is driving nearby shape `0x04D0` objects into a specific equip/activation mode. ### Branch 2: frame != 0 This branch only runs if `Item::I_isOnScreen(arg_06)` passes. It then performs another nearby search, this time using `item->family` with family value `6`. Inside that scan it uses: - `Actor::I_isNPC(...)` - `Item::I_getZ(...)` - a vertical-band test of `origin_z - 10 < candidate_z < origin_z + 10` The exact truth sense of the `Actor::I_isNPC` step is still slightly uncertain because we are reading it through the current pseudo-IR condition simplifier, but the script is clearly trying to qualify nearby actor-like entities in the same local vertical band before proceeding. If that actor/family gate succeeds, the script runs a second nearby shape search for `item->shape == 0x04D0`, again requiring frame `0` on the found object, then calls: ```text Item::I_equip(pid, 0x15, item) ``` followed by `suspend`. So the non-zero-frame branch is the more selective mode: it only arms the nearby `0x04D0` helper objects once a local visibility/actor-proximity condition is satisfied. ## What shape `0x04D0` likely is The old disassembly corpus labels usecode class `0x04D0` as `MONSTER`. That does not prove every shape-id use of `0x04D0` is literally a monster actor object, but it is a strong clue that `ALARMHAT` is not interacting with an arbitrary visual prop. It is probably targeting a helper/actor class in the monster or hostile-response lane. This is the strongest reason not to read `ALARMHAT` as just a decorative siren hat sprite. The script is actively scanning for nearby `0x04D0` objects and equipping them. ## Follow-up: what controls immediate spawn versus waiting The nearby `ALARMHAT` logic is only one half of the `0x04D0` story. The matching `MONSTER` class now adds one verified activation rule: - `MONSTER::enterFastArea` only checks `0x04D0` objects when `Item.getFrame(arg_06) == 0` - inside that frame-0 lane it reads `Item.getMapNum(arg_06)` and only auto-runs `MONSTER.equip(pid, 0, arg_06)` when `(mapNum & 0x08) == 0` Current safest read: - `frame 0` = the only state that participates in the automatic `enterFastArea` spawn lane - `mapNum bit 0x08` = suppresses that automatic lane without changing DTABLE row selection - `frame 1` = skips `enterFastArea` entirely and is therefore more likely to be used in paired or externally signaled setups That fits the recurring authored pairs already visible in exported map data: - Remorse map 246: frame-0 `item:162` uses `mapNum = 8`, `npcNum = 0`, while colocated frame-1 `item:163` uses `mapNum = 1`, `npcNum = 8` - Remorse map 9: frame-0 `item:338` uses `mapNum = 0`, `npcNum = 0`, while colocated frame-1 `item:339` uses `mapNum = 7`, `npcNum = 2` This follow-up also narrows one tempting overread: `quality` low byte is not the primary `spawn now vs wait` control in `MONSTER::enterFastArea`. The current Regret `ALARMHAT` body does still compare nearby `0x04D0` `Item.getQLo(...)` values against difficulty lanes `0/1/2`, so low quality remains relevant as a secondary filter, just not as the automatic-enter-area gate. The wider exported corpus now supports keeping that claim local but real. Additional `0x04D0`-adjacent bodies in `ITEM.slot_2D`, `FUSPAC.slot_01`, and `MISS8.slot_20` also scan nearby `0x04D0` objects and branch on frame and/or `Item.getQLo(...)`. Current safest synthesis is therefore: - `frame` plus `mapNum bit 0x08` controls the automatic `MONSTER.enterFastArea` lane - `quality` low byte is still a real local signal key used by several authored trigger/alarm/helper families - but that low byte is not yet proven to be a single universal direct-link field across every `0x04D0` interaction ## Comparison to the rest of the alarm family `ALARMHAT` fits the broader alarm family, but it is not identical to the other alarm classes. ### `ALARM_NS` and `ALARM_EW` These are tiny `enterFastArea` stubs. They mainly stamp info, exclude themselves from processing, and gate on a simple intrinsic. Those look like directional/environment trigger markers. ### `ALRMTRIG` This class is a compact trigger/spawner. Its `equip` body branches on map/state and spawns `class_0A18_slot_20(...)` with different mode values. That looks more like an alarm-event relay. ### `ALARMBOX` This is the closest comparator. `ALARMBOX::equip`: - uses the same `set_info(0x0211)` + `process_exclude()` prologue - branches by local state and frame - spawns different helper slots for low/high alarm states - can also spawn `class_0A18_slot_20(...)` So `ALARMBOX` reads like a more explicit alarm control box, while `ALARMHAT` reads like a local accessory/controller that pushes nearby helper objects into one of two equip states. ## Gameplay interpretation The safest gameplay-facing read is: `ALARMHAT` is an alarm-state accessory or controller item that toggles nearby hostile/helper objects between two alarm-response modes. The second mode only activates when the item is visible on screen and when a nearby actor-like entity qualifies within a narrow Z band, which strongly suggests local encounter awareness rather than a map-global trigger. In practical gameplay terms, the object likely does something like one of these: - wake up or arm nearby hostile responders - switch nearby helper entities between idle and alert states - mark a local alarm point as actively triggered once the player or another actor is nearby The name `ALARMHAT` therefore probably reflects object art or designer shorthand rather than a full behavior description. The script behavior is closer to `alarm accessory that equips nearby monster/helper actors into a response mode` than to `play a siren sound` or `flash a light`. ## Confidence and uncertainty High confidence: - `ALARMHAT` has one live exported body, slot `0x0A equip` - it uses the same `0x0211` alarm-family setup as `ALARMBOX` - it branches on its own frame - it performs nearby searches on shape `0x04D0` - it calls `Item::I_equip(...)` on qualifying found objects with two different mode values: `0x17` and `0x15` - the second mode is gated by on-screen and nearby actor/family checks Moderate confidence: - shape `0x04D0` is a monster/helper/hostile-response class rather than an inert prop - the non-zero-frame branch is the alert or escalation state Lower confidence / still open: - the exact semantic meaning of equip modes `0x17` versus `0x15` - the precise truth sense of the `Actor::I_isNPC`-named intrinsic inside the family-`6` scan - whether `ALARMHAT` is physically a wearable-looking prop, a mounted alarm device, or a small controller object whose art happened to be named `HAT` ## Current best rename-level takeaway Do not rename it yet. But the current best mental model is: `ALARMHAT = local alarm-state driver that equips nearby MONSTER/helper objects into one of two response modes depending on frame/state and nearby actor visibility.`