180 lines
No EOL
7.3 KiB
Markdown
180 lines
No EOL
7.3 KiB
Markdown
# 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.
|
|
|
|
## 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.` |