From 5e1479c7af01a52602ae28bca8eb0e41513dccfd Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Sun, 23 Aug 2026 14:40:26 +0200 Subject: [PATCH 1/3] Expand Gleeok documentation --- constants/seasons/parts.s | 4 +- object_code/seasons/enemies/gleeok.s | 757 ++++++++++++++++----------- object_code/seasons/parts/43.s | 183 ++++--- 3 files changed, 556 insertions(+), 388 deletions(-) diff --git a/constants/seasons/parts.s b/constants/seasons/parts.s index 882a0a9a6..006b249ac 100644 --- a/constants/seasons/parts.s +++ b/constants/seasons/parts.s @@ -94,8 +94,8 @@ .define PART_MOTHULA_PROJECTILE_2 $42 ;; -; created by Gleeok - projectiles? -.define PART_43 $43 +; projectiles created by Gleeok +.define PART_GLEEOK_FLAME $43 ;; ; created by medusa head diff --git a/object_code/seasons/enemies/gleeok.s b/object_code/seasons/enemies/gleeok.s index ea791c392..d4b9407dd 100644 --- a/object_code/seasons/enemies/gleeok.s +++ b/object_code/seasons/enemies/gleeok.s @@ -1,68 +1,94 @@ ; ================================================================================================== ; ENEMY_GLEEOK +; +; Variables (subid 1, main body): +; var30-var37: Contain high bytes of other body parts with subids 2-9 +; var38: Bitfield of which 3 bits are used: +; Bit 0: Set while one of the heads is performing one of the attacks 0-2 to block the other +; head from the same attack range +; Bit 1: Set whenever the left head is detached and floating through the room +; Bit 2: Set whenever the right head is detached and floating through the room +; +; Variables (subids 2 and 3, heads): +; var03: Attack pattern (0-5) +; relatedObj1: Points to the main body +; var30: Angle sequence index for movement in attack patterns 4 and 5 +; var31: Wait timer for next angle update in attack patterns 4 and 5 +; var39: Projectile target y for attack pattern 1 +; var3a: Projectile target x for attack pattern 1 +; +; Variables (subids 4 to 9, neck segments): +; relatedObj1: Points to the main body +; relatedObj2: Points to the head on the same side ; ================================================================================================== enemyCode06: jr z,@normalStatus - sub $03 + sub ENEMYSTATUS_NO_HEALTH ret c jr nz,@normalStatus + ; If main body has no health, consider the boss defeated ld e,Enemy.subid ld a,(de) dec a jp z,enemyBoss_dead - ld e,$a4 + ld e,Enemy.collisionType ld a,(de) or a jp z,enemyDie_uncounted_withoutItemDrop + ; Otherwise a head has no health, mark it as floating in main body variable ld e,Enemy.subid ld a,(de) cp $02 - ld b,$02 + ld b,$02 ; left head jr z,+ - ld b,$04 + ld b,$04 ; right head + - ld a,$38 + ld a,Object.var38 call objectGetRelatedObject1Var ld a,(hl) or b ld (hl),a + ; If this head is currently performing a fire attack and the other head is also attacking, + ; advance the other head to state $0c so it can pick a fire attack soon ld e,Enemy.state ld a,(de) cp $0b jr nz,+ - ld e,$83 + ld e,Enemy.var03 ld a,(de) cp $03 jr nc,+ - ld e,$82 + ld e,Enemy.subid ld a,(de) xor $01 - add $ae + add Enemy.var30-2 ld l,a ld h,(hl) - ld l,$84 + ld l,Enemy.state ld a,(hl) cp $0b jr nz,+ inc (hl) + + ; Put head in state $0e (floating across the room) ld h,d - ld l,$84 + ld l,Enemy.state ld (hl),$0e - ld l,$a4 + ; Reset health and make immune to attacks + ld l,Enemy.collisionType set 7,(hl) inc l - ld (hl),$04 - ld l,$a9 + ld (hl),ENEMYCOLLISION_PODOBOO ; [enemyCollisionMode] + ld l,Enemy.health ld (hl),$19 - ld l,$ac + ld l,Enemy.knockbackAngle ld a,(hl) - ld l,$89 + ld l,Enemy.angle ld (hl),a - ld l,$90 - ld (hl),$50 - ld l,$86 - ld (hl),$96 + ld l,Enemy.speed + ld (hl),SPEED_200 + ld l,Enemy.counter1 + ld (hl),150 xor a jp enemySetAnimation @@ -92,45 +118,50 @@ enemyCode06: .dw @subid8 .dw @subid9 +; Initialize room or body part depending on subid @state0: ld a,b or a - jp z,+ + jp z,@initializeRoom call ecom_setSpeedAndState8AndVisible - jp func_6c6b -+ + jp gleeok_initializeBodyPart + +@initializeRoom: inc a - ld (de),a - ld a,$06 - ld b,$87 + ld (de),a ; [state] + ld a,ENEMY_GLEEOK + ld b,PALH_SEASONS_87 call enemyBoss_initializeRoom +; Spawn the 9 body parts with references between main body and other parts, then delete self @state1: - ld b,$09 + ld b,9 call checkBEnemySlotsAvailable ret nz ld b,ENEMY_GLEEOK call ecom_spawnUncountedEnemyWithSubid01 - ld l,$80 + ld l,Enemy.enabled ld e,l ld a,(de) ld (hl),a - ld l,$b0 + ld l,Enemy.var30 ld c,h - ld e,$08 + ; Spawn 8 enemy objects (2 heads and 6 neck segments) + ld e,8 - push hl call ecom_spawnUncountedEnemyWithSubid01 ld a,$0a sub e - ld (hl),a - ld l,$96 - ld a,$80 + ld (hl),a ; [subid] + ; Make relatedObj1 point to main body + ld l,Enemy.relatedObj1 + ld a,Enemy.start ldi (hl),a ld (hl),c ld a,h pop hl - ldi (hl),a + ldi (hl),a ; [var30] through [var37] dec e jr nz,- jp enemyDelete @@ -138,6 +169,7 @@ enemyCode06: @stateStub: ret +; Main body @subid1: ld a,(de) sub $08 @@ -150,48 +182,53 @@ enemyCode06: .dw @@stateD .dw @@stateE .dw @@stateF - .dw @@stateG - + .dw @@state10 + +; Start playing music once the shutter door is closed @@state8: ld a,(wcc93) or a ret nz ld h,d ld l,e - inc (hl) - ld a,$2e + inc (hl) ; [state] + ld a,MUS_BOSS ld (wActiveMusic),a jp playSound - + +; Wait until both heads are floating @@state9: - ld e,$b8 + ld e,Enemy.var38 ld a,(de) bit 1,a jr z,@@animate bit 2,a jr z,@@animate + ; Both heads are floating, prepare second phase ld h,d - ld l,$84 + ld l,Enemy.state inc (hl) - ld l,$87 - ld (hl),$3c - ld e,$b0 + ld l,Enemy.counter2 + ld (hl),60 + ; Set health of heads to 0 and disable their collision + ld e,Enemy.var30 ld a,(de) ld h,a - ld l,$a9 + ld l,Enemy.health xor a - ld (hl),a - ld l,$a4 + ld (hl),a ; left head + ld l,Enemy.collisionType ld (hl),a inc e - ld a,(de) + ld a,(de) ; [var31] ld h,a xor a - ld (hl),a - ld l,$a9 - ld (hl),a - ld hl,$ce16 - xor a + ld (hl),a ; [collisionType] + ld l,Enemy.health + ld (hl),a ; right head + ; Make floor under main body no longer solid + ld hl,wRoomCollisions+$16 + xor a ; Unnecessary ldi (hl),a ldi (hl),a ld (hl),a @@ -199,11 +236,12 @@ enemyCode06: ldi (hl),a ldi (hl),a ld (hl),a - ld a,$67 + ld a,SND_BOSS_DEAD call playSound - ld a,$f0 + ld a,SNDCTRL_STOPMUSIC jp playSound - + +; Flicker and transition to second phase @@stateA: call ecom_decCounter2 jp nz,ecom_flickerVisibility @@ -211,111 +249,121 @@ enemyCode06: call enemyBoss_spawnShadow jp nz,ecom_flickerVisibility ld h,d - ld l,$84 + ld l,Enemy.state inc (hl) - ld l,$86 - ld (hl),$1e + ld l,Enemy.counter1 + ld (hl),30 ld a,$04 call enemySetAnimation - + +; Start playing music again @@stateB: call ecom_decCounter1 jp nz,ecom_flickerVisibility - inc (hl) + inc (hl) ; [counter1] = 1 ld l,e - inc (hl) - ld l,$a4 + inc (hl) ; [state] + ld l,Enemy.collisionType set 7,(hl) - ld a,$2e + ld a,MUS_BOSS ld (wActiveMusic),a call playSound - ld e,$84 - + ld e,Enemy.state + +; Start jump @@stateC: call ecom_decCounter1 jr nz,+ ld l,e - inc (hl) + inc (hl) ; [state] ld bc,$fdc0 call objectSetSpeedZ jp objectSetVisible81 + - ld a,(hl) - cp $0a + ld a,(hl) ; [counter1] + cp 10 ret c @@animate: jp enemyAnimate - + +; Perform jump and shake the ground when landing @@stateD: ld c,$20 call objectUpdateSpeedZ_paramC ret nz - ld l,$84 + ld l,Enemy.state inc (hl) - ld l,$86 - ld (hl),$96 - ld a,$78 + ld l,Enemy.counter1 + ld (hl),150 + ld a,120 call setScreenShakeCounter call objectSetVisible82 - ld a,$81 + ld a,SND_STRONG_POUND jp playSound - + +; Stun Link if he touches the ground within 15 frames after landing, then after waiting set the angle to face Link @@stateE: call ecom_decCounter1 - jr z,+ - ld a,(hl) - cp $87 + jr z,@@@prepareRunTowardsLink + ld a,(hl) ; [counter1] + cp 135 jr c,@@animate - ld a,($d00f) + ld a,(w1Link.zh) rlca ret c - ld hl,$cc6a + ld hl,wLinkForceState ld a,$14 ldi (hl),a - ld (hl),$00 + ld (hl),$00 ; [wcc50] ret -+ + +@@@prepareRunTowardsLink: ld l,e - inc (hl) - ld l,$90 - ld (hl),$50 + inc (hl) ; [state] + ld l,Enemy.speed + ld (hl),SPEED_200 call ecom_updateAngleTowardTarget jr @@animate - + +; Run until a wall is encountered @@stateF: - ld a,$01 + ld a,$01 ; Holes count as walls call ecom_getSideviewAdjacentWallsBitset - jr nz,+ + jr nz,@@@reachedWall call objectApplySpeed jr @@animate -+ - ld a,$28 + +@@@reachedWall: + ld a,40 call setScreenShakeCounter ld h,d - ld l,$84 + ld l,Enemy.state inc (hl) - ld l,$90 - ld (hl),$14 - ld l,$89 + ld l,Enemy.speed + ld (hl),SPEED_80 + ; Bounce in opposite direction of running + ld l,Enemy.angle ld a,(hl) xor $10 ld (hl),a ld bc,$fe80 call objectSetSpeedZ jr @@animate - -@@stateG: + +; Perform bounce away from wall +@@state10: call ecom_applyVelocityForSideviewEnemyNoHoles ld c,$20 call objectUpdateSpeedZ_paramC jr nz,@@animate - ld l,$84 + ld l,Enemy.state ld (hl),$0c - ld l,$86 - ld (hl),$3c + ld l,Enemy.counter1 + ld (hl),60 jr @@animate +; Left head @subid2: ld a,(de) sub $08 @@ -329,86 +377,98 @@ enemyCode06: .dw @@stateE .dw @@stateF .dw @@incStateWhenCounter1Is0 - .dw @@stateH - + .dw @@state11 + +; Initialize head-specific properties @@state8: ld h,d ld l,Enemy.angle ld (hl),$14 -@@incStateEnableCollisionsSetCounterAndSpeed: +@@@rightHeadEntry: ld l,e - inc (hl) + inc (hl) ; [state] ld l,Enemy.collisionType set 7,(hl) ld l,Enemy.counter1 - ld (hl),$3c + ld (hl),60 ld l,Enemy.speed ld (hl),SPEED_80 ret - + @@incStateWhenCounter1Is0: call ecom_decCounter1 jp nz,objectApplySpeed ld l,e - inc (hl) + inc (hl) ; [state] ret - + +; Pick the next attack pattern @@stateA: ld b,$04 -@@func_6905: - ld a,$38 +@@@rightHeadEntry: + ; If other head is currently floating, pick one of the attacks 0-2 + ld a,Object.var38 call objectGetRelatedObject1Var ld a,(hl) and b ld c,$03 - ld l,$b8 - jr nz,+ + ld l,Enemy.var38 + jr nz,@@@lowAttackPattern ; Confusing order, this branch could have been 2 operations earlier + ; If the other head is doing one of the attacks 0-2, pick an attack 3-5 bit 0,(hl) - jr nz,++ - ld e,$82 + jr nz,@@@highAttackPattern + ; If right head, pick an attack 0-2 + ld e,Enemy.subid ld a,(de) cp $03 - jr z,+ + jr z,@@@lowAttackPattern + ; If right head is in state $10 or $11 (just came back to main body after floating), pick an attack 0-2 ld b,h - ld l,$b1 + ld l,Enemy.var31 ld h,(hl) - ld l,$84 + ld l,Enemy.state ld a,(hl) cp $10 ld h,b - jr nc,+ + jr nc,@@@lowAttackPattern + ; If Link is in the left half of the room, pick an attack 0-2, otherwise 3-5 ldh a,( Date: Sun, 23 Aug 2026 14:46:01 +0200 Subject: [PATCH 2/3] Rename 43.s to gleeokFlame.s --- object_code/seasons/parts/{43.s => gleeokFlame.s} | 0 seasons.s | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename object_code/seasons/parts/{43.s => gleeokFlame.s} (100%) diff --git a/object_code/seasons/parts/43.s b/object_code/seasons/parts/gleeokFlame.s similarity index 100% rename from object_code/seasons/parts/43.s rename to object_code/seasons/parts/gleeokFlame.s diff --git a/seasons.s b/seasons.s index e228c5e61..d48d55ae8 100644 --- a/seasons.s +++ b/seasons.s @@ -690,7 +690,7 @@ m_section_free Part_Code_2 NAMESPACE partCode .include "object_code/seasons/parts/aquamentusProjectile.s" .include "object_code/seasons/parts/dodongoFireball.s" .include "object_code/seasons/parts/mothulaProjectile2.s" - .include "object_code/seasons/parts/43.s" + .include "object_code/seasons/parts/gleeokFlame.s" .include "object_code/seasons/parts/44.s" .include "object_code/seasons/parts/45.s" .include "object_code/seasons/parts/46.s" From 8bc707ff795a0f94203bc90584bf539a1f0123ec Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Mon, 24 Aug 2026 22:12:43 +0200 Subject: [PATCH 3/3] Bring Gleeok subid and state functions to top level --- object_code/seasons/enemies/gleeok.s | 338 ++++++++++++------------ object_code/seasons/parts/gleeokFlame.s | 40 +-- 2 files changed, 190 insertions(+), 188 deletions(-) diff --git a/object_code/seasons/enemies/gleeok.s b/object_code/seasons/enemies/gleeok.s index d4b9407dd..fe9eddae2 100644 --- a/object_code/seasons/enemies/gleeok.s +++ b/object_code/seasons/enemies/gleeok.s @@ -96,30 +96,30 @@ enemyCode06: call ecom_getSubidAndCpStateTo08 jr nc,+ rst_jumpTable - .dw @state0 - .dw @state1 - .dw @stateStub - .dw @stateStub - .dw @stateStub - .dw @stateStub - .dw @stateStub - .dw @stateStub + .dw gleeok_state_uninitialized + .dw gleeok_state_spawner + .dw gleeok_state_stub + .dw gleeok_state_stub + .dw gleeok_state_stub + .dw gleeok_state_stub + .dw gleeok_state_stub + .dw gleeok_state_stub + dec b ld a,b rst_jumpTable - .dw @subid1 - .dw @subid2 - .dw @subid3 - .dw @subid4 - .dw @subid5 - .dw @subid6 - .dw @subid7 - .dw @subid8 - .dw @subid9 + .dw gleeok_body + .dw gleeok_headLeft + .dw gleeok_headRight + .dw gleeok_neckTopLeft + .dw gleeok_neckTopRight + .dw gleeok_neckMiddleLeft + .dw gleeok_neckMiddleRight + .dw gleeok_neckBottomLeft + .dw gleeok_neckBottomRight ; Initialize room or body part depending on subid -@state0: +gleeok_state_uninitialized: ld a,b or a jp z,@initializeRoom @@ -134,7 +134,7 @@ enemyCode06: call enemyBoss_initializeRoom ; Spawn the 9 body parts with references between main body and other parts, then delete self -@state1: +gleeok_state_spawner: ld b,9 call checkBEnemySlotsAvailable ret nz @@ -166,26 +166,26 @@ enemyCode06: jr nz,- jp enemyDelete -@stateStub: +gleeok_state_stub: ret ; Main body -@subid1: +gleeok_body: ld a,(de) sub $08 rst_jumpTable - .dw @@state8 - .dw @@state9 - .dw @@stateA - .dw @@stateB - .dw @@stateC - .dw @@stateD - .dw @@stateE - .dw @@stateF - .dw @@state10 + .dw gleeok_body_state8 + .dw gleeok_body_state9 + .dw gleeok_body_stateA + .dw gleeok_body_stateB + .dw gleeok_body_stateC + .dw gleeok_body_stateD + .dw gleeok_body_stateE + .dw gleeok_body_stateF + .dw gleeok_body_state10 ; Start playing music once the shutter door is closed -@@state8: +gleeok_body_state8: ld a,(wcc93) or a ret nz @@ -197,13 +197,13 @@ enemyCode06: jp playSound ; Wait until both heads are floating -@@state9: +gleeok_body_state9: ld e,Enemy.var38 ld a,(de) bit 1,a - jr z,@@animate + jr z,gleeok_body_animate bit 2,a - jr z,@@animate + jr z,gleeok_body_animate ; Both heads are floating, prepare second phase ld h,d ld l,Enemy.state @@ -242,7 +242,7 @@ enemyCode06: jp playSound ; Flicker and transition to second phase -@@stateA: +gleeok_body_stateA: call ecom_decCounter2 jp nz,ecom_flickerVisibility ld bc,$020c @@ -257,7 +257,7 @@ enemyCode06: call enemySetAnimation ; Start playing music again -@@stateB: +gleeok_body_stateB: call ecom_decCounter1 jp nz,ecom_flickerVisibility inc (hl) ; [counter1] = 1 @@ -271,7 +271,7 @@ enemyCode06: ld e,Enemy.state ; Start jump -@@stateC: +gleeok_body_stateC: call ecom_decCounter1 jr nz,+ ld l,e @@ -284,11 +284,11 @@ enemyCode06: cp 10 ret c -@@animate: +gleeok_body_animate: jp enemyAnimate ; Perform jump and shake the ground when landing -@@stateD: +gleeok_body_stateD: ld c,$20 call objectUpdateSpeedZ_paramC ret nz @@ -303,12 +303,12 @@ enemyCode06: jp playSound ; Stun Link if he touches the ground within 15 frames after landing, then after waiting set the angle to face Link -@@stateE: +gleeok_body_stateE: call ecom_decCounter1 - jr z,@@@prepareRunTowardsLink + jr z,@prepareRunTowardsLink ld a,(hl) ; [counter1] cp 135 - jr c,@@animate + jr c,gleeok_body_animate ld a,(w1Link.zh) rlca ret c @@ -318,23 +318,23 @@ enemyCode06: ld (hl),$00 ; [wcc50] ret -@@@prepareRunTowardsLink: +@prepareRunTowardsLink: ld l,e inc (hl) ; [state] ld l,Enemy.speed ld (hl),SPEED_200 call ecom_updateAngleTowardTarget - jr @@animate + jr gleeok_body_animate ; Run until a wall is encountered -@@stateF: +gleeok_body_stateF: ld a,$01 ; Holes count as walls call ecom_getSideviewAdjacentWallsBitset - jr nz,@@@reachedWall + jr nz,@reachedWall call objectApplySpeed - jr @@animate + jr gleeok_body_animate -@@@reachedWall: +@reachedWall: ld a,40 call setScreenShakeCounter ld h,d @@ -349,42 +349,42 @@ enemyCode06: ld (hl),a ld bc,$fe80 call objectSetSpeedZ - jr @@animate + jr gleeok_body_animate ; Perform bounce away from wall -@@state10: +gleeok_body_state10: call ecom_applyVelocityForSideviewEnemyNoHoles ld c,$20 call objectUpdateSpeedZ_paramC - jr nz,@@animate + jr nz,gleeok_body_animate ld l,Enemy.state ld (hl),$0c ld l,Enemy.counter1 ld (hl),60 - jr @@animate + jr gleeok_body_animate ; Left head -@subid2: +gleeok_headLeft: ld a,(de) sub $08 rst_jumpTable - .dw @@state8 - .dw @@incStateWhenCounter1Is0 - .dw @@stateA - .dw @@stateB - .dw @@stateC - .dw @@stateD - .dw @@stateE - .dw @@stateF - .dw @@incStateWhenCounter1Is0 - .dw @@state11 + .dw gleeok_headLeft_state8 + .dw gleeok_head_state9 + .dw gleeok_headLeft_stateA + .dw gleeok_head_stateB + .dw gleeok_head_stateC + .dw gleeok_head_stateD + .dw gleeok_head_stateE + .dw gleeok_head_stateF + .dw gleeok_head_state10 + .dw gleeok_head_state11 ; Initialize head-specific properties -@@state8: +gleeok_headLeft_state8: ld h,d ld l,Enemy.angle ld (hl),$14 -@@@rightHeadEntry: +@rightHeadEntry: ld l,e inc (hl) ; [state] ld l,Enemy.collisionType @@ -395,7 +395,9 @@ enemyCode06: ld (hl),SPEED_80 ret -@@incStateWhenCounter1Is0: +; Increment state when counter1 reaches 0 after decrementing +gleeok_head_state9: +gleeok_head_state10: call ecom_decCounter1 jp nz,objectApplySpeed ld l,e @@ -403,9 +405,9 @@ enemyCode06: ret ; Pick the next attack pattern -@@stateA: +gleeok_headLeft_stateA: ld b,$04 -@@@rightHeadEntry: +@rightHeadEntry: ; If other head is currently floating, pick one of the attacks 0-2 ld a,Object.var38 call objectGetRelatedObject1Var @@ -413,15 +415,15 @@ enemyCode06: and b ld c,$03 ld l,Enemy.var38 - jr nz,@@@lowAttackPattern ; Confusing order, this branch could have been 2 operations earlier + jr nz,@lowAttackPattern ; Confusing order, this branch could have been 2 operations earlier ; If the other head is doing one of the attacks 0-2, pick an attack 3-5 bit 0,(hl) - jr nz,@@@highAttackPattern + jr nz,@highAttackPattern ; If right head, pick an attack 0-2 ld e,Enemy.subid ld a,(de) cp $03 - jr z,@@@lowAttackPattern + jr z,@lowAttackPattern ; If right head is in state $10 or $11 (just came back to main body after floating), pick an attack 0-2 ld b,h ld l,Enemy.var31 @@ -430,32 +432,32 @@ enemyCode06: ld a,(hl) cp $10 ld h,b - jr nc,@@@lowAttackPattern + jr nc,@lowAttackPattern ; If Link is in the left half of the room, pick an attack 0-2, otherwise 3-5 ldh a,(