546 - bombShield(int a, int script)
Sets the bomb invulnerability flag (a=0 false, a=1 true), the caller's ANM script will change to script when a bomb is active.
611 - etEx(int etId, int async, int type, float a, float b)
Adds bullet transformation to bullet manager etId, Transformation of flag type determines the specific behaviour of the bullet. Documentation can be found here.
BulletEffectType-67108864 - etExDelay(string et, string isAsync, string time)
Hide the bullet for time frames. During this time, it will not move, will be invisible and won't have a hitbox. If used as a first transformation, can be used to delay when the bullet actually appears.
6 - isDelayedSpawn
While this flag is set, the bullet will be invisible and not have a hitbox. This flag is cleared once the delay timer ends.
4 - short_timer
Integer value between -1 and 15 inclusive (by default -1). If non-negative, shooters using short_timer shoot their bullets and timer increments by 1 per frame until 15 is reached. Once 15, timer reset to -1 or 0 depending on Z key state.
5 - long_timer
Integer value between -1 and 120 inclusive (by default -1). If non-negative, shooters using long_timer shoot their bullets and timer increments by 1 per frame until 120 is reached. Once 120, timer reset to -1 or 0 depending on Z key state.
91 - floatTime(int slot, float var, int time, int mode, float start, float final)
In time frames using mode mode, variable var changes from start to final. slot is used to set the slot to be used by this ins, every enemy has 8 slots.
-9980 - F1
Local float variable, inherited by spawned enemies.
-9984 - I1
Local integer variable, inherited by spawned enemies.
-9989 - ANGLE_PLAYER
Angle from the enemy to the player.
-9962 - BOSS_Y
Final Y position of the boss.
-9990 - PLAYER_Y
Player's Y position.
-9963 - BOSS_X
Final X position of the boss.
-9991 - PLAYER_X
Player's X position.
81 - circlePos(float varX, float varY, float angle, float radius)
Performs following operation: varX = cos(angle) * radius and varY = cos(angle) * radius
-9981 - F0
Local float variable, inherited by spawned enemies.
300 - enmCreate(string sub, float x, float y, int hp, int score, int item)
Creates an enemy using subroutine sub at coordinates (x, y) (relative to position of the parent), health of created enemy is hp, score bonus is score and item drop is item.
601 - etOn(int etId)
Shoots bullet(s) using properties from bullet manager etId.
23 - wait(int time)
Stops sub execution for time frames.
1 - delete()
Returns to the top of current call stack.
Dragon Eater Timeout
Specifications
- Versions:
1.00a
- Difficulty:
Easy-Normal-Hard-Lunatic-Extra
- Mode:
Main game -
Practice mode-Spell practice
- Shottype:
Reimu -
Marisa -
Sakuya -
Sanae
- Cards: None
What happens
Momoyo's 8th spell-card is a spell-card that is aimed at the player and spawns a cluster of bullets that fire at a random direction from where the player was previously at. There is a bug in which Momoyo continues to spawn a cluster of bullets that are never-ending. This phenomenon appears at around the ~20.00 second mark. Momoyo continues to attack the player as she normally does, meaning that the amount of clusters of bullets increases. She continues firing new waves until the spell ends.

How it happens
There are two requirements to be met for this bug to be triggered:
- The player must time down Momoyo's 8th spell-card for at least 60 seconds.
- The player must NOT be at an incredibly precise angle relative to Momoyo. The reason for this is explained in the next paragraph.
Why it happens
The information provided in this section is obtained by decompiling the st07bs.ecl file through using thecl with a premade eclmap. In the following section, all instruction names will be explained. Furthermore, if you want to read more about what the instructions do, you can search it up in the following page.
Momoyo's subroutines
Momoyo's 8th spell-card uses several subroutines to do her attacks. A subroutine is a set of instructions designed to perform a frequently used operation within a program. The following relevant subroutines to Momoyo's 8th spell-card are as follows:
void BossCard8() {
[...]
floatTime(0, %F1, 3600, 0, 3.0f, 30.0f);
loop {
$I1 = _S(%F1);
@BossCard8_at();
}
}
void BossCard8_at() {
var ANGLE;
[...]
%ANGLE = %ANGLE_PLAYER - 3.1415927f;
circlePos(%F0, %F1, %ANGLE + 1.0471976f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE + 0.5235988f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE - 0.5235988f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE - 1.0471976f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
return;
}
void BossCard8_et() {
var DECREMENT;
[...]
$DECREMENT = $I1;
BossCard8_et_1040:
etAngle(1, %A, 0.0f);
%A = %A + 3.883222f;
validRad(%A);
etDist(1, %RANDF2 * _f(32));
etOn(1);
wait(3);
BossCard8_et_1284:
if ($DECREMENT--) goto BossCard8_et_1040 @ 0;
delete();
}
All the aforementioned code is explained in the following section. Also, the important instructions will be highlighted !
Code Explanation
BossCard8is what Momoyo is currently.BossCard8_atis what Momoyo attacks with. In this case, it only spawns an enemy calledBossCard8_et.BossCard8_etis the invisible enemy that is spawned byBossCard8_at.BossCard8_etis the one that spawns bullets.BossCard8_etdespawns after a certain time.
In short, Momoyo uses the code at BossCard8 to spawn invisible enemies called BossCard8_et that shoot the bullets BossCard8_at.
BossCard8
For convenience, the code is posted below again:
void BossCard8() {
[...]
floatTime(0, %F1, 3600, 0, 3.0f, 30.0f);
loop {
$I1 = _S(%F1);
@BossCard8_at();
}
}
The instruction floatTime does the following:
In time frames using mode mode, variable var changes from start to final.
Instruction does the following: The float variable floatTime(0, %F1, 3600, 0, 3.0f, 30.0f)F1 is defined and updated every frame for 3600 frames long. Its initial value is 3.0 and its final value is 30.0. This takes a total of 3600 frames and it is done linearly (so on frame t the variable F1 is equal to 27/3600*t+3).
The line $ declares the integer variable I1 = _S(%F1)I1, which is equal to the float value of F1 but converted to an integer and rounded down. This action is looped.
The line @BossCard8_at() calls for the subroutine BossCard8_at. This action is looped.
BossCard8_at
For convenience, the code is posted below again:
void BossCard8_at() {
var ANGLE;
[...]
%ANGLE = %ANGLE_PLAYER - 3.1415927f;
circlePos(%F0, %F1, %ANGLE + 1.0471976f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE + 0.5235988f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE - 0.5235988f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
circlePos(%F0, %F1, %ANGLE - 1.0471976f, 1400.0f);
enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);
return;
}
The float variable ANGLE is given the value , where ANGLE_PLAYER - 3.1415927fANGLE_PLAYER is the angle between the parent object (in this case Momoyo) and the player.
ANGLE_PLAYER is calculated as follows: ANGLE_PLAYER = arctan2(BOSS_Y - PLAYER_Y, BOSS_X - PLAYER_X)
The instruction performs the following two actions: circlePos(float varX, float varY, float ang, float radius)varX = cos(ang) * radius and varY = sin(ang) * radius
The instruction performs the following two actions: circlePos(%F0, %F1, %ANGLE + 1.0471976f, 1400.0f) and F0 = cos(ANGLE + 1.0471976f) * 1400.0F0 = sin(ANGLE + 1.0471976f) * 1400.0
The instruction enmCreate is quite complicated, so it will be summarised in this page. To put it simply, creates an enemy enmCreate("BossCard8_et", 0.0f, 0.0f, 100, 0, 0);BossCard8_et at Momoyo's position.
The return keyword tells Momoyo to go back to the subroutine BossCard8 where she will keep looping her attacking.
BossCard8_et
For convenience, the code is posted below again:
void BossCard8_et() {
var DECREMENT;
[...]
$DECREMENT = $I1;
BossCard8_et_1040:
[...]
etOn(1);
wait(3);
BossCard8_et_1284:
if ($DECREMENT--) goto BossCard8_et_1040 @ 0;
delete();
}
The integer variable DECREMENT is declared and is assigned the value I1, which was declared in the subroutine BossCard8.
Instruction makes the bullets spawn. In this case, etOn(int id) spawns the arrowhead bullets.etOn(1)
Instruction stops the subroutine execution for wait(int time);time frames, so stops the execution time for 3 frames.wait(3)
Instruction deletes the caller once called. In this case, the subroutine delete();BossCard8_et destroys itself once called.
Although it is written quite obtusely, the end part of subroutine BossCard8_et keeps shooting bullets through instruction until the integer variable etOn(1)DECREMENT is exactly equal to 0. The variable DECREMENT decreases by 1 every iteration.
Cause of Bullet spam
Instruction writes to the variable floatTime(0, %F1, 3600, 0, 3.0f, 30.0f)F1 for exactly 3600 frames. However, once those 3600 frames have passed, the variable F1 is no longer updated by the instruction floatTime.
Instead, the variable F1 is set by the instruction circlePos, where . This means that the amount of bullets spawning depends on the F1 = sin(A - 1.0471976f) * 1400.0 = sin(ANGLE_PLAYER - 4.1887903f) * 1400.0ANGLE_PLAYER value. Following this, the value I1 is equal to F1 but I1 is an integer. The variable DECREMENT is equal to the value of I1.
The invisible enemy bullet spawner BossCard8_et only despawns if DECREMENT is equal to 0. This means that the value DECREMENT must be low enough where the variable DECREMENT is in the range [0, 30] such that it doesn't go on infinitely (30 is chosen here because that is its intended maximum value that ZUN set according to floatTime). For DECREMENT to be low enough, the value I1 must be low enough. For I1 to be low enough, the value of F1 must be low enough. For F1 to be low enough, sin( must be low enough.ANGLE_PLAYER -1.0471977f) * 1400.0
To give an estimate how precisely-small ANGLE_PLAYER for there to be no bullet spam, the angles will be calculated for when there are a total of 0 and 30 lingering bullets.
For there to be exactly 0 lingering bullets, the variable ANGLE_PLAYER must be around 1.0471977.
For there to be exactly 30 lingering bullets, the variable ANGLE_PLAYER must be around 1.0686279.
If the variable ANGLE_PLAYER were any higher, then the integer variable DECREMENT is a much higher value. This means that the invisible enemy bullet spawner would have to shoot a few thousand bullets before it despawns. Furthermore, if the variable ANGLE_PLAYER were any lower, then the integer variable DECREMENT is a negative value. It means that the value would have to underflow, meaning it has to go through a few billion iterations before the invisible enemy bullet spawner despawns.
To visualise how precise the angles are, I have modified the stage such that Momoyo shoots lasers that are at the aforementioned angles. Anything outside the lasers gives the player waves that are going to last a while:

In order to humanely timeout this spell, the player must be between the two lasers when Momoyo is spawning the invisible bullet spawning enemies. This is humanely impossible to do considering Momoyo constantly moves around alongside the difficulty of the spell.
Conclusion
Links
Replays
This section has no content yet. Would you like to add to this section? Contact me if you are interested!
Videos
- Notaco. 「March 31, 2023」. "Touhou UM - Momoyo Oomukade "Dragon Eater" Timeout [TAS]" https://www.youtube.com/watch?v=IBU67XMK1FA
- dannan14. 「July 21, 2024」. "[TAS] Touhou 18 - Unconnected Marketeers - Dragon Eater Timeout" https://www.youtube.com/watch?v=Nb1_943sBJE
All Unconnected Marketeers pages: | |
|---|---|
| Slowdown Item Duplication · Chimata Final Timeout Crash · D press Desync · Takane Card Cost · No Bombs in Practice Mode · Centipede + Wolf cards combination · Lily White Crash · Dragon Eater Timeout · Momoyo's Final Bomb Damage · (Sub-)shottypes Not Functioning · Shield Method of the Youkai Laser Misalignment · Shop Manipulation · Incorrect Playtime · Koishi Card Desync · Equipment Cards Desync · Momoyo Card Desync · Byakuren Card Desync · Eirin/Eiki Card Purchase Crash · Eirin Card Deactivation | All Ecl-related pages: |