This note records the casting behavior compiled into the legally owned local HP1 packages. It intentionally paraphrases the embedded UnrealScript instead of copying proprietary source into the repository.
The primary evidence is:
res/System/DefUser.inires/System/HarryPotter.u:Harry,skHarryres/System/HPBase.u:baseHarry,Target,baseWand,baseSpell,spellnone,spelldud,spellFlip,SpellLearnTriggerres/System/HPParticle.u:TargetGlowres/System/HProps.u:FloatingSpellBookres/System/Engine.u: compiled defaults forPawn
The embedded ScriptText was inspected locally with strings -a -n 1, then
behavioral claims were checked against the compiled function bytecode and
class defaults through the package and script decoders. This distinction
matters: several statements remain in ScriptText but have no corresponding
compiled calls. Do not commit extracted source or generated dumps.
DefUser.ini maps LeftMouse to the AltFire alias. The alias both updates
the held bAltFire button and invokes the AltFire exec, so the press enters
aiming and the state later observes release as bAltFire == 0.
Its MouseY binding feeds aMouseY with positive speed. HP1's UE1 rotator
convention maps positive pitch toward positive Z.
Harry.AltFire rejects the press when Harry is frozen or falling, the HUD is
in cutscene mode, a boss encounter has disabled casting, Harry has no weapon,
the press was already handled, or he is carrying something. It does not
require a spell target. An accepted press:
- marks the weapon as pointing;
- sets
bJustAltFired; - enters
Harry.PlayerAiming.
Although the embedded text still shows an initial PlaySound and
weapon.altfire(1), neither call exists in compiled Harry.AltFire bytecode.
baseWand.AltFire exists as a function, but the ordinary compiled Harry input
path does not invoke it.
On entry, compiled PlayerAiming.BeginState calls DebugState, resets
fTimeToStop, and calls StartSoundFX. Compiled StartSoundFX plays
spell_build_nl2 and the looping spell_loop_nl. The embedded text's
MovementMode(true) and HAR_raise_arm calls are absent from the compiled
BeginState bytecode.
The state body always calls Harry.makeTarget, loops Harry's wave
animation, and marks the wand as casting. makeTarget spawns an
HPBase.Target 50 Unreal units ahead of Harry and gives it a reference back
to Harry. This happens whether or not any castable world actor exists.
While the button remains held, the Target actor ticks and moves the aiming
particles. On release, the state stops the build/loop sound, plays Harry's
cast animation at rate 2 with a 0.1 tween, waits until its frame reaches
0.95, and returns to PlayerWalking.
Both skHarry and skSmallHarry attach an animation notify to cast at
normalized time 0.1. That notify invokes Harry.Cast. There is no
target-dependent animation branch in PlayerAiming: the packaged script uses
the same cast sequence for success and failure.
HPBase.Target.setTarget runs every tick. In ordinary play its ray:
- starts at Harry's location, not at the camera;
- uses Harry's yaw plus a separate target pitch;
- reaches 512 units, or 1024 when
bExtendedTargettingis enabled; - clamps pitch to
-8000...12000rotator units; - changes pitch from
SmoothMouseY / 8once the absolute input exceeds 256.
Normal targeting keeps the target's yaw offset at zero, so horizontal mouse input turns Harry and therefore the ray. The separate yaw offset is used by locked boss targeting.
The acquisition order is:
- Iterate
TraceActorsalong the ray and stop at the first actor whosebProjTargetorbBlockActorsis true. - If that finds nothing, call
baseHarry.ExtendTarget. - If auto-aim also finds nothing, perform a normal
Traceso the free reticle can rest on world geometry; if that misses too, use the ray endpoint.
ExtendTarget considers visible bProjTarget actors other than the player
and BaseCam. A candidate must be strictly within 4000 rotator units in both
yaw and pitch and no farther than 512 units. The nearest qualifying candidate
wins. Four thousand rotator units are about 22 degrees, so the authored
auto-aim cone is deliberately broad.
The target test itself is bProjTarget; neither setTarget nor
ExtendTarget checks Harry's learned-spell list. A blocking actor occludes
auto-aim through the direct trace path. A selected projectile target receives
its Targeted event, becomes Target.victim, and is passed to
Target.LockOn.
LockOn sizes the reticle from the victim's world collision box and
SizeModifier, then asks the wand to choose the victim's
eVulnerableToSpell. It also obtains that chosen spell's gesture. Moving the
mouse outside the cone makes the next tick's victim selection start over;
the script does not set Harry's general bLockedOnTarget flag for ordinary
auto-aim. That flag is reserved for boss-style targeting. Losing the victim
calls the unlock path, which shuts down an active gesture effect; moving far
enough away therefore releases the snap and removes the target gesture.
Target.startup always creates two HPParticle.TargetGlow children. One is
red and one cyan; the Target emitter supplies the third component of the
floating aiming feedback. Each tick moves all three emitters to the traced,
auto-aimed, or free endpoint.
The spell-shaped gesture is separate. Target.DrawSpellFX is reached from
LockOn, after a bProjTarget victim has been selected and its vulnerability
has chosen a spell. Most targets display the gesture while aiming. A
baseChar with bGestureOnTargeting == false defers that gesture until the
target actor leaves its state during release.
No-target aiming does not call LockOn and therefore must not create a spell
gesture. This distinction is important because spellnone and spelldud
carry misleading compiled display defaults: both are named “Flipendo” and
reference FlipPattern. Those defaults do not make a no-target Flipendo
gesture authored behavior.
Destroying Target destroys both glow children and calls StopEffect.
StopEffect shuts down an active gesture, plays spell_off_target3, and
stops spell_targetloop.
Harry.Cast, invoked by the animation notify, uses the victim maintained by
the Target tick. A once-present final call to ExtendTarget is commented
out in the packaged source and is not part of the compiled release behavior.
With a victim, Harry.Cast passes that actor to baseWand.CastSpell. Without
a victim, it passes the reticle actor itself. The latter is intentional: it
provides a direction and target point for the failed cast.
The compiled baseWand default has bAutoSelectSpell == true, and
baseWand.BeginPlay sets bUseNoSpell == true. CastSpell therefore selects
the supplied actor's eVulnerableToSpell immediately before firing:
- a real vulnerable target selects its matching spell;
- the no-target reticle inherits
SPELL_None, which makesChooseSpellselectspellnone.
The relevant direct mappings are SPELL_Flipendo to spellFlip and
SPELL_Alohomora to spellAloho; the switch also covers the other shipped
spell types. During the special underAttack path, Harry.Cast instead
chooses the attacker's vulnerability and uses baseWand.forcespell, bypassing
normal auto-selection for that shot.
Compiled spellnone defaults use the spell_dud cast sound, a short
SmokeExplo_03 flying effect, and a 0.3-second lifespan. This is the authored
failure cast. It is not spellFlip, even though the class's legacy UI name
and gesture fields still say Flipendo.
After choosing the spell, CastSpell fires it, assigns its homing target and
original caster, and plays an incantation when applicable. Harry.Cast then
destroys the reticle.
Compiled Harry.PostBeginPlay adds only spelldud; this makes spelldud the
initial curSpell. The embedded text still contains temporary calls adding
spellFlip and spellAloho and selecting spellFlip, but those three calls
are absent from the compiled bytecode. In either case, the current selection
does not control a normal targeted cast: CastSpell auto-selects from the
current target immediately before firing.
SpellLearnTrigger.Trigger adds its configured spell at the start of the
lesson and selects it; the source notes that the lesson cannot be failed.
FloatingSpellBook.Touch also adds its configured spell. The only other
packaged use of spellList is spell-list UI and manual selection.
Neither baseWand.ChooseSpell nor target lock-on checks whether the chosen
class appears in spellList. In the shipped logic, progression is enforced
primarily by level state and which actors are exposed as bProjTarget with a
particular vulnerability, not by a new cast-input guard. Reimplementing a
learned-spell check in the input path would diverge from the original scripts.
Engine.Pawn has compiled defaults bCollideActors == true,
bBlockActors == true, and bProjTarget == true; Harry inherits them.
OpenHP1 had reversed the authored Start and End arguments before running
TraceActors. The backwards sweep approached Harry at the terminal end of the
ray and falsely selected him as the victim. That false lock-on selected
spellnone, read its legacy FlipPattern, and drew a Flipendo-shaped gesture
at Harry.
UE1 traces from Start toward End. OpenHP1's shared actor sweep already
omits an actor overlapping the trace origin, so preserving the authored
direction also preserves the original result: Harry is not returned by the
ray that begins at his location. This belongs at the shared
TraceActors/collision seam, not in PlayerAiming or a Harry-specific casting
guard.
The auto-aim fallback has a separate authored self-filter. Compiled
ExtendTarget rejects a visible candidate when it equals Self. OpenHP1's VM
represents Self internally with a sentinel object handle, but implicit native
calls had compared that sentinel literally instead of resolving it to the
current actor. The filter consequently admitted Harry whenever his own
location fell inside the auto-aim cone. Resolving Self at the common actor
call boundary restores the compiled comparison and other actor calls that pass
Self; no casting-specific exclusion is needed.
Independently, every accepted aim must spawn and update Target plus both
TargetGlow actors even when no valid target exists. Missing free-aim
particles are therefore a particle spawning, ticking, tracing, or projection
defect—not intended spell-progression behavior.
| Package | Compiled object | Relevant evidence |
|---|---|---|
HarryPotter.u |
Harry class export 43 |
AltFire 8, PostBeginPlay 175, makeTarget 672, PlayerAiming state 915, Cast 992 |
HarryPotter.u |
skHarry class export 902 |
cast animation notify calls Cast at 0.1 |
HPBase.u |
baseHarry class export 0 |
ExtendTarget function 2913 |
HPBase.u |
Target class export 321 |
seeking state 2268, setTarget 2310, DrawSpellFX 2385, StopEffect 1937, Destroyed 2406 |
HPBase.u |
baseWand class export 25 |
ChooseSpell 2017, CastSpell 2021; compiled bAutoSelectSpell=true |
HPBase.u |
spell classes | spellFlip 225, spellnone 1290, spelldud 1313 |
HPParticle.u |
TargetGlow |
red/cyan glow setup and lock/unlock particle sizing |
Engine.u |
Pawn |
compiled collision and projectile-target defaults inherited by Harry |