Prev: 40757 Up: Map Next: 41264
40826: UpdateAlien
Per-frame driver for the alien's combat behaviour. The alien itself does still attack crew directly elsewhere in the per-frame chain — this routine specifically handles the **first-encounter activation of the Android**: once the alien is loose and meets the alien_target slot for the first time, this routine pulls that slot into action state 7 (attack), turning the Android from a normal-looking crew member into a hostile actor that wounds nearby crew.
Input
Returns immediately if any of:
- AlienActiveFlag (33704) == 0 (alien not yet loose / no encounter)
- alien_target's byte +0 != 0 (Android already activated; the
activation stamp at 40849 sets +0 = 80, so on every subsequent
frame this guard short-circuits the routine)
- alien_target's byte +7 != 0 (lockout sentinel — CrewHitsAndroid's
collapse path at 41039 writes +7 = 2, and that prevents
re-activation if the Android has been defeated)
In other words: the routine fires exactly ONCE per game for the Android, the first frame the alien is active and the slot is still in its as-issued template state (LongGameCrewInit, 41444, gives +0 = +7 = 0 for every slot). That single firing is the "encounter". When all guards pass: 1. IX = alien_target record; stamp (IX+0) = 80 (activation marker and timer that also blocks future re-entry into this branch). 2. Cache AlienTargetID into CrewIndex (33700) for downstream message enqueues. 3. CALL 37876 — scan crew records 1..7 for slots sharing the Android's (IX+1) sprite-class and write up to two slot indices into NearestCrewA / NearestCrewB (the Android's "kin" — its attack pool). 4. If at least one of NearestCrewA/B is alive: enqueue message #30 "{actor} is attacking {target}" with actor = AlienTargetID (the Android's name, e.g. "Ash is attacking Lambert"), put the alien_target into action state 7 with timer 40, then return. 5. If neither kin is reachable, fall through to 36717 (wander) and reset the Android to action state 1. Once the Android is in state 7, subsequent ResetCrewTimers frames dispatch it through CrewAction7_Handler (40757) which decrements the wound counter on its NearestCrewA/B kin and can collapse them via 39400 (msg #21 "{actor} has collapsed"). This routine is NOT the alien's own attack: the alien kills crew that end up in its room (slot 0 record byte +1) — see CrewHitsAlien (37584) and the kill primitive at 37733. Used by the routine at 36457.
40826 LD A,(33704) A = AlienActiveFlag
40829 AND A alien loose on ship?
40830 RET Z no: no encounter yet, nothing to activate
40831 LD HL,(33701) HL = alien_target record (AlienTargetPtr)
40834 LD A,(HL) A = byte +0
40835 AND A Android already activated (+0 stamped to 80)?
40836 RET NZ yes: this routine has already fired once, skip
40837 LD DE,7 offset to byte +7 (defeated-lockout sentinel)
40840 ADD HL,DE HL → +7
40841 CP (HL) A=0 here; Z iff byte +7 == 0 (template, not defeated)
40842 RET NZ +7 != 0: Android collapsed earlier, stay dormant
40843 PUSH IX save caller's IX
40845 LD IX,(33701) IX = Android record (= alien_target)
40849 LD (IX+0),80 stamp +0 = 80 — activation marker / blocks re-entry
40853 LD A,(33703) A = AlienTargetID (= Android slot index)
40856 LD (33700),A CrewIndex = AlienTargetID (Android's slot)
40859 CALL 37876 pick the Android's two sprite-class kin as targets
40862 LD A,(33696) A = nearest crew ID 1 (33696)
40865 CP 255 $FF = no crew in range
40867 JR Z,40906 no primary target: wander
40869 LD C,A C = crew ID
40870 ADD A,A A × 8 (crew record size)
40871 ADD A,A
40872 ADD A,A
40873 LD E,A
40874 LD D,0
40876 LD HL,29573 HL = crew alive-table base ($7385)
40879 ADD HL,DE HL → NearestCrewA's alive-flag byte
40880 XOR A A = 0
40881 CP (HL) Z iff (HL) == 0 (which is the "alive" value here)
40882 JR Z,40920 NearestCrewA alive: attack them
40884 LD A,(33697) A = NearestCrewB
40887 CP 255
40889 JR Z,40906 no secondary target either: wander
40891 LD C,A
40892 ADD A,A
40893 ADD A,A
40894 ADD A,A
40895 LD E,A
40896 LD D,0
40898 LD HL,29573 crew alive-table base
40901 ADD HL,DE
40902 XOR A
40903 CP (HL) Z iff NearestCrewB's flag == 0 (alive)
40904 JR Z,40920 alive: attack them
40906 CALL 36717 no reachable crew: alien wanders
40909 LD (IX+3),1 Android slot → action state 1 (idle/wander)
40913 LD (IX+0),60 with timer 60 frames
40917 POP IX
40919 RET
40920 LD H,C H = nearest-crew ID (message target)
40921 LD A,(33703) A = AlienTargetID
40924 LD L,A L = Android slot index (message actor)
40925 LD A,30 A = message #30 "{actor} is attacking {target}"
40927 CALL 37176 enqueue: "{Android name} is attacking {nearest}"
40930 LD (IX+3),7 Android slot → action state 7 (attack)
40934 LD (IX+0),40 with timer 40 frames (next dispatch runs the attack)
40938 POP IX
40940 RET
CrewHitsAndroid — combat-resolution dialogue when the current actor engages the Android (called from CrewAction4_Handler at 37542). Fires from action state 4 (combat) when the actor's (IX+1) sprite-class byte matches the alien-target slot's (IX+1). Because (IX+1) is not unique in LongGameCrewInit (41444), this fires for the whole class that contains the Android (see CrewAction4_Handler header) — multiple crew members can trigger this routine, not only the Android itself. The Android is the slot picked by LongGameInit (42276) from LongGameTargetTable (41390) and stored in AlienTargetID (33703), record pointer cached at AlienTargetPtr (33701). It starts dormant and is activated by UpdateAlien (40826) on first encounter with the alien (the first frame AlienActiveFlag is set while the slot's +0/+7 are still template-zero), entering action state 7 and wounding its sprite-class kin via CrewAction7_Handler (40757). This routine is the **player-response leg**: when the Android (or another crew in its sprite class) is engaged in combat state 4, log the dialogue and apply the per-corridor-cell outcome. Guards: pixel coords IX+4 >= 2 and IX+6 >= 2 (actor placed on screen). Then 31823 locates the actor's corridor scan position into (31248): (31248) == 17 → silent: JP to 41229 (post-combat fade-out) (31248) >= 20 → silent: JP to 41229 (sentinel cells) (31248) == 16 → "net" outcome: write $FF to alien-target slot byte +0 (locks the Android out for the rest of this engagement), then enqueue message #31 "{actor} nets {target}" with actor = CrewIndex (33700) — the crew slot currently being dispatched — and target high byte from (33702). JP to 41229. else → "hit" outcome at 40999: enqueue message #32 "{actor} hits the Android" with actor = CrewIndex. Then run the per-(31248) follow-up: - decrement alien-target's byte +4 (wound counter); if it underflows past 2, stamp byte +7 = 2 (lockout sentinel that prevents UpdateAlien re-commandeering on subsequent frames, see UpdateAlien's byte-+7 gate at 40841) and enqueue message #21 "{Android} has collapsed" - if (31248) ∈ {6, 7}: enqueue message #5 "{actor}'s Tracker is broken" - if (31248) < 12: decrement the slot's entry in ItemCharges (33746) and enqueue message #6 if it expires - other (31248) values branch into the corridor-display rebuild at 41109 / 41195 (clears the Android's class entries from the corridor display and respawns the room) Caveat on the actor name: when (33700) is itself the Android's slot (the dispatch ran for the Android slot), the message reads "{Android} hits the Android" — apparent self-reference. With the class-not-ID matching above, the message ALSO fires for non-Android slots in the same class, e.g. "Lambert hits the Android" if AlienTargetID = 4 (Ash). The semantics here are best confirmed with an emulator run rather than further static reading. This routine is the parallel of 37584 (CrewHitsAlien) — identical control flow but referring to the Android slot (33701) and emitting messages #31 / #32 instead of #3 / #4.
40941 LD A,(IX+4) A = actor pixel X-tile
40944 CP 2
40946 RET C X-tile < 2 → not yet placed: bail
40947 LD A,(IX+6) A = actor pixel Y
40950 CP 2
40952 RET C Y < 2 → bail
40953 LD A,(33700) A = CrewIndex (slot being dispatched)
40956 CALL 31823 populate (31248)/(31249) with corridor positions
40959 LD A,(31248) A = scan position in 22-byte anim table
40962 CP 17
40964 JP Z,41229 pos 17 → silent post-combat
40967 CP 20
40969 JP NC,41229 pos >= 20 → silent (sentinel cells)
40972 CP 16
40974 JR NZ,40999 pos != 16 → "hits the Android" branch
40976 LD HL,(33701) HL = alien-target (Android) slot pointer
40979 LD (HL),255 lock Android's byte +0 = $FF for this engagement
40981 CALL 37924
40984 LD A,(33700) A = CrewIndex
40987 LD HL,(33702) H = high byte of AlienTargetPtr
40990 LD L,A L = actor (CrewIndex)
40991 LD A,31 A = msg #31 "{actor} nets {target}"
40993 CALL 37176 enqueue
40996 JP 41229
"{actor} hits the Android" branch (CrewHitsAndroid continued).
40999 PUSH AF stash (31248) for the post-message dispatch
41000 LD A,(33700) A = CrewIndex (slot being dispatched)
41003 LD L,A L = actor for the message
41004 LD A,32 A = msg #32 "{actor} hits the Android"
41006 CALL 37176 enqueue
41009 POP AF A = (31248) restored
41010 CP 6
41012 JR C,41022
41014 CP 18
41016 JR Z,41022
41018 CP 19
41020 JR NZ,41062
41022 LD HL,(33701)
41025 LD DE,4
41028 ADD HL,DE
41029 DEC (HL)
41030 LD A,(HL)
41031 CP 2
41033 JP NC,41229
41036 INC HL
41037 INC HL
41038 INC HL
41039 LD (HL),2
41041 LD DE,65529
41044 ADD HL,DE
41045 LD (HL),0
41047 LD A,(33703)
41050 LD L,A
41051 LD A,21
41053 CALL 37176
41056 CALL 45148
41059 LD (HL),0
41061 RET
41062 CP 8
41064 JR NC,41079
41066 CALL 37924
41069 LD A,5
41071 LD HL,(33700)
41074 CALL 37176
41077 JR 41022
41079 CP 12
41081 JR NC,41109
41083 LD HL,33746
41086 LD E,A
41087 LD D,0
41089 ADD HL,DE
41090 LD A,(HL)
41091 AND A
41092 JR Z,41098
41094 DEC (HL)
41095 JP 41229
41098 LD HL,(33700)
41101 LD A,6
41103 CALL 37176
41106 JP 41229
41109 JP NZ,41195
41112 CALL 37876
41115 LD DE,33695
41118 LD B,3
41120 PUSH BC
41121 PUSH DE
41122 LD A,(DE)
41123 CP 255
41125 JR Z,41179
41127 PUSH AF
41128 ADD A,128
41130 LD E,A
41131 ADD A,32
41133 LD D,A
41134 LD C,(IX+1)
41137 LD HL,29940
41140 LD B,22
41142 LD A,(HL)
41143 CP D
41144 JR Z,41152
41146 CP E
41147 JR Z,41152
41149 CP C
41150 JR Z,41154
41152 LD (HL),255
41154 INC HL
41155 DJNZ 41142
41157 POP AF
41158 LD HL,29573
41161 ADD A,A
41162 ADD A,A
41163 ADD A,A
41164 LD E,A
41165 LD D,0
41167 ADD HL,DE
41168 XOR A
41169 CP (HL)
41170 JR NZ,41179
41172 LD (HL),1
41174 LD DE,65529
41177 ADD HL,DE
41178 LD (HL),A
41179 POP DE
41180 INC DE
41181 POP BC
41182 DJNZ 41120
41184 LD A,15
41186 LD E,(IX+1)
41189 CALL 38186
41192 JP 31417
41195 LD E,A
41196 LD D,0
41198 LD HL,33746
41201 ADD HL,DE
41202 XOR A
41203 CP (HL)
41204 JR Z,41218
41206 DEC (HL)
41207 LD A,6
41209 LD E,(IX+1)
41212 CALL 38186
41215 JP 41022
41218 LD HL,(33700)
41221 LD A,7
41223 CALL 37176
41226 JP 41229
41229 LD A,(31252)
41232 CP 1
41234 RET NZ
41235 LD A,(31241)
41238 LD HL,33700
41241 CP (HL)
41242 RET NZ
41243 LD A,(33704)
41246 AND A
41247 LD A,(HL)
41248 RET Z
41249 LD A,52
41251 CALL 45269
41254 LD HL,18646
41257 LD (31257),HL
41260 CALL 31634
41263 RET
Prev: 40757 Up: Map Next: 41264